From bdd59fb2401438bc6f5978442c00486808e695c5 Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Wed, 9 Sep 2026 18:10:00 -0700 Subject: [PATCH 1/9] CI: install Pytest, SQLite bindings on FreeBSD in a more stable way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This essentially cherry picks an improvement from Rumur.¹ ¹ https://github.com/Smattr/rumur/commit/dc1edfbae4bf065574786eb9b2984e875a5a8181 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 028c8c34..0616cdd4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: set -u set -x uname -rms - pkg install -y bash cmake cscope git llvm python3 py311-pytest sqlite3 py311-sqlite3 vim + pkg install -y bash cmake cscope git llvm python3 devel/py-pytest sqlite3 databases/py-sqlite3 vim python3 --version git clone --no-checkout --recurse-submodules -- ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} wd cd wd From bea22f6baa10cdd69d5dbc23ed2caec1ee58650b Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Wed, 9 Sep 2026 18:28:22 -0700 Subject: [PATCH 2/9] clink_db_open: preserve const-correctness across 'strrchr' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC+Glibc on Ubuntu 26.04 seems to apply C23 rules to this code and propagate the const-ness of the input across `strrchr`: libclink/src/db_open.c: In function ‘clink_db_open’: libclink/src/db_open.c:261:19: error: initialization discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers] 261 | char *slash = strrchr(path, '/'); | ^~~~~~~ Reported-by: GCC 15.2.0 -Wdiscarded-qualifiers --- libclink/src/db_open.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libclink/src/db_open.c b/libclink/src/db_open.c index 322f67a8..c4ad1df6 100644 --- a/libclink/src/db_open.c +++ b/libclink/src/db_open.c @@ -258,7 +258,7 @@ int clink_db_open(clink_db_t **db, const char *path) { slash[1] = '\0'; d->dir = abs; } else { - char *slash = strrchr(path, '/'); + const char *const slash = strrchr(path, '/'); d->dir = strndup(path, (size_t)(slash + 1 - path)); d->filename = strdup(slash + 1); } From 2904406d85ccc0e7857e4ea258f8a93066b790e7 Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Wed, 9 Sep 2026 18:17:50 -0700 Subject: [PATCH 3/9] CI: migrate Linux job to Github Actions At this point, Cirrus CI is well and truly dead. Its domain is unreachable. --- .cirrus.yml | 11 ----------- .github/workflows/ci.yml | 18 ++++++++++++++++++ misc/ci.sh | 8 +------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 7042decf..9b20757a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -4,17 +4,6 @@ task: only_if: $CIRRUS_BRANCH == "main" || $CIRRUS_PR != "" matrix: - - name: Linux - container: - image: gcc:15.1 - environment: - DEBIAN_FRONTEND: noninteractive - CFLAGS: -Werror -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=undefined -fuse-ld=gold - LC_ALL: C.UTF-8 - UBSAN_OPTIONS: print_stacktrace=1 - install_script: apt-get update -y && apt-get install --no-install-recommends -y cmake cscope libclang-dev llvm python3-pytest sqlite3 xxd vim - test_script: ./misc/ci.sh - - name: Linux, release build container: image: gcc:15.1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0616cdd4..bb7df48d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,3 +37,21 @@ jobs: printf "find-me says: " ./build/test/find-me/find-me cmake --install build + + ubuntu2604: + name: Linux + runs-on: ubuntu-26.04 + env: + DEBIAN_FRONTEND: noninteractive + CFLAGS: -Werror -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=address,undefined + UBSAN_OPTIONS: print_stacktrace=1 + steps: + - run: sudo apt-get update + - run: sudo apt-get install --no-install-recommends -y cscope libclang-dev llvm python3-pytest xxd vim + - run: echo "cloning ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" + - run: git clone --no-checkout --recurse-submodules -- ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} wd + - run: > + cd wd && + git fetch -- origin ${{ github.event.pull_request.head.sha }} && + git checkout FETCH_HEAD && + ./misc/ci.sh diff --git a/misc/ci.sh b/misc/ci.sh index 00609d6f..5a131cf0 100755 --- a/misc/ci.sh +++ b/misc/ci.sh @@ -17,10 +17,4 @@ cmake --build build --target check printf "find-me says: " ./build/test/find-me/find-me -if [ "$(uname -s)" = "Darwin" ]; then - SUDO=sudo -else - # sudo not needed - SUDO= -fi -${SUDO} cmake --install build +sudo cmake --install build From ae929d1788784a0bb4bfccbe22427c83f54f179c Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Wed, 9 Sep 2026 18:39:19 -0700 Subject: [PATCH 4/9] CI: migrate Linux release job to Github Actions Cirrus CI is dead. --- .cirrus.yml | 12 ------------ .github/workflows/ci.yml | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 9b20757a..175ba140 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -4,18 +4,6 @@ task: only_if: $CIRRUS_BRANCH == "main" || $CIRRUS_PR != "" matrix: - - name: Linux, release build - container: - image: gcc:15.1 - environment: - DEBIAN_FRONTEND: noninteractive - CFLAGS: -Werror -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=undefined -fuse-ld=gold - CMAKE_FLAGS: -DCMAKE_BUILD_TYPE=Release - LC_ALL: C.UTF-8 - UBSAN_OPTIONS: print_stacktrace=1 - install_script: apt-get update -y && apt-get install --no-install-recommends -y cmake cscope libclang-dev llvm python3-pytest sqlite3 xxd vim - test_script: ./misc/ci.sh - - name: macOS macos_instance: image: ghcr.io/cirruslabs/macos-runner:sequoia diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb7df48d..670d5358 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,3 +55,22 @@ jobs: git fetch -- origin ${{ github.event.pull_request.head.sha }} && git checkout FETCH_HEAD && ./misc/ci.sh + + ubuntu2604_release: + name: Linux, release build + runs-on: ubuntu-26.04 + env: + DEBIAN_FRONTEND: noninteractive + CFLAGS: -Werror -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=address,undefined + CMAKE_FLAGS: -DCMAKE_BUILD_TYPE=Release + UBSAN_OPTIONS: print_stacktrace=1 + steps: + - run: sudo apt-get update + - run: sudo apt-get install --no-install-recommends -y cscope libclang-dev llvm python3-pytest xxd vim + - run: echo "cloning ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" + - run: git clone --no-checkout --recurse-submodules -- ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} wd + - run: > + cd wd && + git fetch -- origin ${{ github.event.pull_request.head.sha }} && + git checkout FETCH_HEAD && + ./misc/ci.sh From 795ba3eb272daf31267556335f6580f7f8950da8 Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Wed, 9 Sep 2026 18:43:11 -0700 Subject: [PATCH 5/9] CI: migrate macOS job to Github Actions Cirrus CI is dead. --- .cirrus.yml | 10 ---------- .github/workflows/ci.yml | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 175ba140..bc99f191 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -4,16 +4,6 @@ task: only_if: $CIRRUS_BRANCH == "main" || $CIRRUS_PR != "" matrix: - - name: macOS - macos_instance: - image: ghcr.io/cirruslabs/macos-runner:sequoia - environment: - CFLAGS: -Werror -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=undefined - PATH: /opt/homebrew/opt/llvm/bin:${PATH} - UBSAN_OPTIONS: print_stacktrace=1 - install_script: brew update && brew install coreutils cscope llvm && env PIP_BREAK_SYSTEM_PACKAGES=1 python3 -m pip install pytest - test_script: ./misc/ci.sh - - name: C formatting container: image: silkeh/clang:19 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 670d5358..1a36c547 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,25 @@ jobs: ./build/test/find-me/find-me cmake --install build + macos26: + name: macOS + runs-on: macos-26-intel + env: + CFLAGS: -Werror -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=address,undefined + UBSAN_OPTIONS: print_stacktrace=1 + steps: + - run: python3 --version + - run: brew update + - run: brew install coreutils cscope llvm + - run: env PIP_BREAK_SYSTEM_PACKAGES=1 python3 -m pip install pytest + - run: echo "cloning ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" + - run: git clone --no-checkout --recurse-submodules -- ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} wd + - run: > + cd wd && + git fetch -- origin ${{ github.event.pull_request.head.sha }} && + git checkout FETCH_HEAD && + ./misc/ci.sh + ubuntu2604: name: Linux runs-on: ubuntu-26.04 From 74e68cfaa9a71e7e3c2cdc343408b95616985391 Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Wed, 9 Sep 2026 17:01:15 -0700 Subject: [PATCH 6/9] =?UTF-8?q?rename=20vim.h=20=E2=86=92=20editor.h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for this file containing non-Vim related things. Github: #285 “When opening a file with the editor Jump to the line of code” --- libclink/include/clink/clink.h | 2 +- libclink/include/clink/{vim.h => editor.h} | 0 libclink/src/editor_open.c | 2 +- libclink/src/is_editor_vim.c | 2 +- libclink/src/vim_open.c | 2 +- libclink/src/vim_read.c | 2 +- libclink/src/vim_read_into.c | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename libclink/include/clink/{vim.h => editor.h} (100%) diff --git a/libclink/include/clink/clink.h b/libclink/include/clink/clink.h index 20b0ce05..5561376d 100644 --- a/libclink/include/clink/clink.h +++ b/libclink/include/clink/clink.h @@ -17,10 +17,10 @@ #include #include #include +#include #include #include #include #include #include #include -#include diff --git a/libclink/include/clink/vim.h b/libclink/include/clink/editor.h similarity index 100% rename from libclink/include/clink/vim.h rename to libclink/include/clink/editor.h diff --git a/libclink/src/editor_open.c b/libclink/src/editor_open.c index d11e0b74..51517b16 100644 --- a/libclink/src/editor_open.c +++ b/libclink/src/editor_open.c @@ -1,5 +1,5 @@ #include "run.h" -#include +#include #include #include diff --git a/libclink/src/is_editor_vim.c b/libclink/src/is_editor_vim.c index f167b25c..d96ec229 100644 --- a/libclink/src/is_editor_vim.c +++ b/libclink/src/is_editor_vim.c @@ -1,6 +1,6 @@ #include "debug.h" #include -#include +#include #include #include #include diff --git a/libclink/src/vim_open.c b/libclink/src/vim_open.c index aaae49ea..c82c8321 100644 --- a/libclink/src/vim_open.c +++ b/libclink/src/vim_open.c @@ -2,7 +2,7 @@ #include "debug.h" #include "run.h" #include -#include +#include #include #include #include diff --git a/libclink/src/vim_read.c b/libclink/src/vim_read.c index 1f12b224..974cc8fb 100644 --- a/libclink/src/vim_read.c +++ b/libclink/src/vim_read.c @@ -1,5 +1,5 @@ #include "debug.h" -#include +#include #include #include #include diff --git a/libclink/src/vim_read_into.c b/libclink/src/vim_read_into.c index 4f38971f..c6eb27d6 100644 --- a/libclink/src/vim_read_into.c +++ b/libclink/src/vim_read_into.c @@ -6,7 +6,7 @@ #include "sql.h" #include #include -#include +#include #include #include #include From 9f50adc52d7db9799452a23102709ebcd8d4460c Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Wed, 9 Sep 2026 17:01:15 -0700 Subject: [PATCH 7/9] add a way to check if editor is Emacs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Github: #285 “When opening a file with the editor Jump to the line of code” --- libclink/CMakeLists.txt | 2 +- libclink/include/clink/editor.h | 6 ++++ libclink/src/{is_editor_vim.c => is_editor.c} | 35 ++++++++++++++++++- 3 files changed, 41 insertions(+), 2 deletions(-) rename libclink/src/{is_editor_vim.c => is_editor.c} (65%) diff --git a/libclink/CMakeLists.txt b/libclink/CMakeLists.txt index 7e471cfb..2d34be0f 100644 --- a/libclink/CMakeLists.txt +++ b/libclink/CMakeLists.txt @@ -31,7 +31,7 @@ add_library(libclink src/get_environ.c src/get_id.c src/have_cscope.c - src/is_editor_vim.c + src/is_editor.c src/iter.c src/make_relative_to.c src/mmap.c diff --git a/libclink/include/clink/editor.h b/libclink/include/clink/editor.h index 5172b0f5..4a28b75f 100644 --- a/libclink/include/clink/editor.h +++ b/libclink/include/clink/editor.h @@ -36,6 +36,12 @@ CLINK_API int clink_vim_open(const char *filename, unsigned long lineno, unsigned long colno, const char *cscopeprg, const clink_db_t *db); +/** does the user’s editor look like Emacs? + * + * \return True if the editor appears Emacs-alike + */ +CLINK_API bool clink_is_editor_emacs(void); + /** open the given editor with the given file * * This is a simple wrapper around exec-ing `{editor, "--", filename}`. This is diff --git a/libclink/src/is_editor_vim.c b/libclink/src/is_editor.c similarity index 65% rename from libclink/src/is_editor_vim.c rename to libclink/src/is_editor.c index d96ec229..29c7fe9b 100644 --- a/libclink/src/is_editor_vim.c +++ b/libclink/src/is_editor.c @@ -9,7 +9,7 @@ * * \param base Start of the path to test * \param length Number of bytes in the path - * \param alias An alias for Vim + * \param alias An alias for Emacs or Vim * \return True if this is a path to a binary of the given alias */ static bool is(const char *base, size_t length, const char *alias) { @@ -67,3 +67,36 @@ bool clink_is_editor_vim(void) { return false; } + +bool clink_is_editor_emacs(void) { + + // priority 1: `$VISUAL` + const char *editor = getenv("VISUAL"); + + // priority 2: `$EDITOR` + if (editor == NULL) + editor = getenv("EDITOR"); + + // else fallback to Vim + if (editor == NULL) + editor = "vim"; + + // `$EDITOR` can contain something like “emacs -q”, so assume only the first + // word is the actual path + const char *space = strchr(editor, ' '); + const size_t len = space == NULL ? strlen(editor) : (size_t)(space - editor); + + // aliases Emacs goes by + const char *EMACS_NAMES[] = {"emacs"}; + + for (size_t i = 0; i < sizeof(EMACS_NAMES) / sizeof(EMACS_NAMES[0]); ++i) { + if (is(editor, len, EMACS_NAMES[i])) { + DEBUG("editor \"%s\" matched \"%s\"", editor, EMACS_NAMES[i]); + return true; + } else { + DEBUG("editor \"%s\" did not match \"%s\"", editor, EMACS_NAMES[i]); + } + } + + return false; +} From 9e1f22aadecb4bc55ae28531131ae82695a1754a Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Wed, 9 Sep 2026 17:01:15 -0700 Subject: [PATCH 8/9] add a way to run Emacs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Github: #285 “When opening a file with the editor Jump to the line of code” --- libclink/CMakeLists.txt | 1 + libclink/include/clink/editor.h | 10 +++++++ libclink/src/emacs_open.c | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 libclink/src/emacs_open.c diff --git a/libclink/CMakeLists.txt b/libclink/CMakeLists.txt index 2d34be0f..e60bb600 100644 --- a/libclink/CMakeLists.txt +++ b/libclink/CMakeLists.txt @@ -28,6 +28,7 @@ add_library(libclink src/eat_num.c src/eat_rest_of_line.c src/editor_open.c + src/emacs_open.c src/get_environ.c src/get_id.c src/have_cscope.c diff --git a/libclink/include/clink/editor.h b/libclink/include/clink/editor.h index 4a28b75f..e01b2f6a 100644 --- a/libclink/include/clink/editor.h +++ b/libclink/include/clink/editor.h @@ -42,6 +42,16 @@ CLINK_API int clink_vim_open(const char *filename, unsigned long lineno, */ CLINK_API bool clink_is_editor_emacs(void); +/** open Emacs at the given position in the given file + * + * \param filename File to open with Emacs + * \param lineno Line number to position cursor at within the file + * \param colno Column number to position cursor at within the file + * \return Emacs’s exit status + */ +CLINK_API int clink_emacs_open(const char *filename, unsigned long lineno, + unsigned long colno); + /** open the given editor with the given file * * This is a simple wrapper around exec-ing `{editor, "--", filename}`. This is diff --git a/libclink/src/emacs_open.c b/libclink/src/emacs_open.c new file mode 100644 index 00000000..7a31496a --- /dev/null +++ b/libclink/src/emacs_open.c @@ -0,0 +1,50 @@ +#include "debug.h" +#include "run.h" +#include +#include +#include +#include + +int clink_emacs_open(const char *filename, unsigned long lineno, + unsigned long colno) { + + // check filename is valid + if (ERROR(filename == NULL)) + return EINVAL; + + // check line number is valid + if (ERROR(lineno == 0)) + return EINVAL; + + // check column number is valid + if (ERROR(colno == 0)) + return EINVAL; + + int rc = 0; + char *jump = NULL; + + // construct a directive telling Emacs to jump to the given position + if (ERROR(asprintf(&jump, "+%lu:%lu", lineno, colno) < 0)) { + rc = ENOMEM; + goto done; + } + + // assume the user’s preferred editor is Emacs, but still locate the path to + // it + const char *emacs = getenv("VISUAL"); + if (emacs == NULL) + emacs = getenv("EDITOR"); + if (emacs == NULL) + emacs = "emacs"; + + // construct a argument vector to invoke Emacs + char const *argv[] = {emacs, jump, "--", filename, NULL}; + + // run it + rc = run(argv); + +done: + free(jump); + + return rc; +} From b55bb9cb10910998a4fc068c0a23fa615c1ff83d Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Wed, 9 Sep 2026 17:01:15 -0700 Subject: [PATCH 9/9] when editor is Emacs, open that instead of Vim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Github: #285 “When opening a file with the editor Jump to the line of code” Reported-by: Github user dtscbs --- clink/src/ui.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clink/src/ui.c b/clink/src/ui.c index eae71cc7..de25da2f 100644 --- a/clink/src/ui.c +++ b/clink/src/ui.c @@ -941,6 +941,10 @@ static int handle_select(void) { results.rows[select_index].lineno, results.rows[select_index].colno, clink_repl, clink_repl == NULL ? NULL : database); + } else if (clink_is_editor_emacs()) { + (void)clink_emacs_open(results.rows[select_index].path, + results.rows[select_index].lineno, + results.rows[select_index].colno); } else { (void)open_editor(results.rows[select_index].path); }