diff --git a/.cirrus.yml b/.cirrus.yml index 7042decf..bc99f191 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -4,39 +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 - 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 - 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 028c8c34..1a36c547 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 @@ -37,3 +37,59 @@ jobs: printf "find-me says: " ./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 + 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 + + 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 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); } diff --git a/libclink/CMakeLists.txt b/libclink/CMakeLists.txt index 7e471cfb..e60bb600 100644 --- a/libclink/CMakeLists.txt +++ b/libclink/CMakeLists.txt @@ -28,10 +28,11 @@ 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 - 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/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 84% rename from libclink/include/clink/vim.h rename to libclink/include/clink/editor.h index 5172b0f5..e01b2f6a 100644 --- a/libclink/include/clink/vim.h +++ b/libclink/include/clink/editor.h @@ -36,6 +36,22 @@ 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 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/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); } 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/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; +} diff --git a/libclink/src/is_editor_vim.c b/libclink/src/is_editor.c similarity index 64% rename from libclink/src/is_editor_vim.c rename to libclink/src/is_editor.c index f167b25c..29c7fe9b 100644 --- a/libclink/src/is_editor_vim.c +++ b/libclink/src/is_editor.c @@ -1,6 +1,6 @@ #include "debug.h" #include -#include +#include #include #include #include @@ -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; +} 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 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