├── .github ├── FUNDING.yml └── workflows │ ├── build-terminal-shared-object.yml │ ├── generate-document.yml │ └── test.yml ├── .gitignore ├── CONTRIBUTING.md ├── ChangeLog.md ├── Dockerfile ├── LICENCE ├── Makefile ├── README.md ├── STYLEGUIDE.md ├── contrib ├── README.md ├── bracket-paren-mode │ ├── bracket-paren-mode.lisp │ └── lem-bracket-paren-mode.asd ├── calc-mode │ ├── lem-calc-mode.asd │ ├── main.lisp │ └── project.lisp ├── fbar │ ├── Readme.md │ ├── fbar.lisp │ └── lem-fbar.asd ├── google-translate │ ├── README.md │ ├── lem-google-translate.asd │ ├── main.lisp │ └── project.lisp ├── lem-contrib.asd ├── migemo │ ├── lem-migemo.asd │ ├── main.lisp │ └── project.lisp ├── modeline-battery │ ├── lem-modeline-battery.asd │ └── main.lisp ├── mouse-sgr1006 │ ├── lem-mouse-sgr1006.asd │ ├── main.lisp │ └── project.lisp ├── ollama │ ├── README.md │ ├── lem-ollama.asd │ ├── listener.lisp │ ├── ollama.lisp │ └── project.lisp ├── overwrite-mode │ ├── lem-overwrite-mode.asd │ └── overwrite-mode.lisp ├── selection-mode │ ├── lem-selection-mode.asd │ ├── project.lisp │ └── selection-mode.lisp ├── tetris │ ├── lem-tetris.asd │ └── tetris.lisp ├── trailing-spaces │ ├── lem-trailing-spaces.asd │ └── trailing-spaces.lisp └── version-up │ ├── lem-version-up.asd │ ├── project.lisp │ └── version.lisp ├── default.nix ├── docker ├── Dockerfile-rpc └── entrypoint.sh ├── docs └── default-keybindings.md ├── extensions ├── asciidoc-mode │ ├── asciidoc-mode.lisp │ └── lem-asciidoc-mode.asd ├── asm-mode │ ├── asm-mode.lisp │ └── lem-asm-mode.asd ├── c-mode │ ├── c-mode.lisp │ ├── format.lisp │ ├── grammar.lisp │ └── lem-c-mode.asd ├── coalton-mode │ ├── coalton-mode.lisp │ └── lem-coalton-mode.asd ├── color-preview │ ├── color-preview.lisp │ └── lem-color-preview.asd ├── copilot │ ├── client.lisp │ ├── copilot.lisp │ ├── install.lisp │ ├── languages.lisp │ ├── lem-copilot.asd │ ├── logger.lisp │ ├── sign-in.lisp │ ├── test-commands.lisp │ └── utils.lisp ├── css-mode │ ├── css-mode.lisp │ └── lem-css-mode.asd ├── dart-mode │ ├── dart-mode.lisp │ └── lem-dart-mode.asd ├── documentation-mode │ ├── documentation-mode.lisp │ ├── internal.lisp │ ├── lem-documentation-mode.asd │ └── utils.lisp ├── dot-mode │ ├── dot-mode.lisp │ └── lem-dot-mode.asd ├── elisp-mode │ ├── elisp-mode.lisp │ ├── lem-elisp-mode.asd │ ├── rpc.lisp │ └── run-elisp.lisp ├── elixir-mode │ ├── elixir-mode.lisp │ ├── lem-elixir-mode.asd │ ├── lsp-config.lisp │ └── run-elixir.lisp ├── encodings │ ├── 8bit.lisp │ ├── cp1250.table │ ├── cp1251.table │ ├── cp1253.table │ ├── cp1254.table │ ├── cp1255.table │ ├── cp1256.table │ ├── cp1257.table │ ├── cp866.table │ ├── cp932.lisp │ ├── cp932.table │ ├── encodings-table │ │ ├── 8bit.lisp │ │ ├── euc.lisp │ │ ├── lem-encodings-table.asd │ │ ├── main.lisp │ │ └── sjis.lisp │ ├── euc-jp.lisp │ ├── euc-jp.table │ ├── gb2312.lisp │ ├── gb2312.table │ ├── iso-8859-1.lisp │ ├── iso-8859-13.table │ ├── iso-8859-2.table │ ├── iso-8859-5.table │ ├── iso-8859-6.table │ ├── iso-8859-7.table │ ├── iso-8859-8.table │ ├── iso-8859-9.table │ ├── koi8-r.table │ ├── koi8-u.table │ ├── lem-encodings.asd │ ├── project.lisp │ ├── table.lisp │ ├── utf-16.lisp │ └── utf-8.lisp ├── erlang-mode │ ├── README.md │ ├── erlang-mode.lisp │ ├── lem-erlang-mode.asd │ ├── lsp-config.lisp │ └── run-erlang.lisp ├── go-mode │ ├── go-mode.lisp │ ├── go.json │ ├── lem-go-mode.asd │ └── lsp-config.lisp ├── haskell-mode │ ├── haskell-mode.lisp │ └── lem-haskell-mode.asd ├── html-mode │ ├── html-mode.lisp │ └── lem-html-mode.asd ├── java-mode │ ├── java-mode.lisp │ └── lem-java-mode.asd ├── js-mode │ ├── eslint.lisp │ ├── js-mode.lisp │ ├── lem-js-mode.asd │ └── lsp-config.lisp ├── json-mode │ ├── json-mode.lisp │ └── lem-json-mode.asd ├── language-client │ ├── client.lisp │ ├── lem-language-client.asd │ └── request.lisp ├── language-server │ ├── cli.lisp │ ├── commands.lisp │ ├── config.lisp │ ├── controller │ │ ├── commands.lisp │ │ ├── document-synchronization.lisp │ │ ├── language-features.lisp │ │ ├── lifecycle.lisp │ │ ├── window.lisp │ │ └── workspace.lisp │ ├── editor-utils.lisp │ ├── eval.lisp │ ├── lem-language-server.asd │ ├── method.lisp │ ├── micros-client.lisp │ ├── package.lisp │ ├── server.lisp │ └── text-document.lisp ├── legit │ ├── README.md │ ├── legit-commit.lisp │ ├── legit-common.lisp │ ├── legit-rebase.lisp │ ├── legit.lisp │ ├── lem-legit.asd │ ├── lem-status.png │ ├── peek-legit.lisp │ ├── porcelain-fossil.lisp │ ├── porcelain-git.lisp │ ├── porcelain-hg.lisp │ ├── porcelain.lisp │ ├── scripts │ │ └── dumbrebaseeditor.sh │ └── test.txt ├── lem-base16-themes │ ├── LICENSE │ ├── README.md │ ├── lem-base16-themes-generate.asd │ ├── lem-base16-themes.asd │ ├── src │ │ ├── generate.lisp │ │ ├── macros.lisp │ │ ├── package.lisp │ │ └── themes.lisp │ └── templates │ │ └── default.mustache ├── lem-dashboard │ ├── dashboard-items.lisp │ ├── default-dashboard.lisp │ ├── lem-dashboard.asd │ └── lem-dashboard.lisp ├── lisp-mode │ ├── apropos-mode.lisp │ ├── connection.lisp │ ├── connections.lisp │ ├── errors.lisp │ ├── ext │ │ ├── autodoc.lisp │ │ ├── class-browser.lisp │ │ ├── completion.lisp │ │ ├── connection-list.lisp │ │ ├── defstruct-to-defclass.lisp │ │ ├── detective.lisp │ │ ├── eval.lisp │ │ ├── exporter.lisp │ │ ├── highlight.lisp │ │ ├── hyperspec.lisp │ │ ├── inspector.lisp │ │ ├── macroexpand.lisp │ │ ├── organize-imports.lisp │ │ ├── package-inferred-system.lisp │ │ ├── paren-coloring.lisp │ │ ├── quickdocs.lisp │ │ ├── self-insert-hook.lisp │ │ ├── sldb.lisp │ │ ├── test-runner.lisp │ │ ├── trace.lisp │ │ └── utopian.lisp │ ├── file-conversion.lisp │ ├── grammar.lisp │ ├── implementation.lisp │ ├── internal-package.lisp │ ├── lem-lisp-mode.asd │ ├── lisp-mode.lisp │ ├── message-definitions.lisp │ ├── message-dispatcher.lisp │ ├── message.lisp │ ├── package.lisp │ ├── read-only-sources.lisp │ ├── reader.lisp │ ├── repl.lisp │ ├── rpc.lisp │ ├── test-api.lisp │ ├── ui-mode.lisp │ └── v2 │ │ └── lsp-config.lisp ├── lisp-syntax │ ├── defstruct-to-defclass.lisp │ ├── enclosing.lisp │ ├── indent.lisp │ ├── lem-lisp-syntax.asd │ ├── lem-lisp-syntax.lisp │ ├── misc.lisp │ ├── parse-for-autodoc.lisp │ └── syntax-table.lisp ├── lsp-base │ ├── converter.lisp │ ├── lem-lsp-base.asd │ ├── protocol-3-17.lisp │ ├── protocol-generator.lisp │ ├── type.lisp │ ├── utils.lisp │ └── yason-utils.lisp ├── lsp-mode │ ├── async-process-stream.lisp │ ├── client-capabilities.json │ ├── client.lisp │ ├── lem-lsp-mode.asd │ ├── lem-stdio-transport.lisp │ ├── lsp-mode.lisp │ └── spec.lisp ├── lua-mode │ ├── lem-lua-mode.asd │ ├── lsp-config.lisp │ └── lua-mode.lisp ├── makefile-mode │ ├── lem-makefile-mode.asd │ └── makefile-mode.lisp ├── markdown-mode │ ├── example.md │ ├── internal.lisp │ ├── languages.lisp │ ├── lem-markdown-mode.asd │ ├── markdown-mode.lisp │ ├── preview │ │ ├── external-browser-preview.html │ │ ├── external-browser.lisp │ │ ├── html-buffer.lisp │ │ └── preview.lisp │ └── syntax-parser.lisp ├── nim-mode │ ├── lem-nim-mode.asd │ └── nim-mode.lisp ├── nix-mode │ ├── indent.lisp │ ├── lem-nix-mode.asd │ └── nix-mode.lisp ├── ocaml-mode │ ├── lem-ocaml-mode.asd │ └── ocaml-mode.lisp ├── paredit-mode │ ├── lem-paredit-mode.asd │ ├── paredit-mode.lisp │ └── tests │ │ └── main.lisp ├── patch-mode │ ├── lem-patch-mode.asd │ └── patch-mode.lisp ├── posix-shell-mode │ ├── lem-posix-shell-mode.asd │ └── posix-shell-mode.lisp ├── process │ ├── lem-process.asd │ ├── package.lisp │ ├── process.lisp │ └── stream.lisp ├── python-mode │ ├── lem-python-mode.asd │ ├── python-mode.lisp │ └── run-python.lisp ├── review-mode │ ├── lem-review-mode.asd │ └── review-mode.lisp ├── ruby-mode │ ├── lem-ruby-mode.asd │ └── ruby-mode.lisp ├── rust-mode │ ├── lem-rust-mode.asd │ └── rust-mode.lisp ├── scala-mode │ ├── lem-scala-mode.asd │ └── scala-mode.lisp ├── scheme-mode │ ├── errors.lisp │ ├── eval.lisp │ ├── grammar.lisp │ ├── lem-scheme-mode.asd │ ├── lem-scheme-syntax.lisp │ ├── package.lisp │ ├── repl.lisp │ ├── scheme-mode.lisp │ ├── swank-connection.lisp │ ├── swank-protocol.lisp │ ├── syntax-data.lisp │ ├── syntax-indent.lisp │ ├── syntax-misc.lisp │ ├── syntax-parse.lisp │ └── syntax-syntax-table.lisp ├── shell-mode │ ├── lem-shell-mode.asd │ └── shell-mode.lisp ├── sql-mode │ ├── lem-sql-mode.asd │ ├── sql-mode.lisp │ └── sql.tmLanguage.json ├── swift-mode │ ├── lem-swift-mode.asd │ ├── lsp-config.lisp │ ├── swift-mode.lisp │ └── swift.json ├── terminal │ ├── Dockerfile │ ├── Dockerfile.musl │ ├── ffi.lisp │ ├── lem-terminal.asd │ ├── lib │ │ ├── linux │ │ │ └── x64 │ │ │ │ └── terminal.so │ │ └── macosx │ │ │ └── arm64 │ │ │ └── terminal.so │ ├── terminal-mode.lisp │ ├── terminal.c │ └── terminal.lisp ├── terraform-mode │ ├── example.tf │ ├── indent.lisp │ ├── lem-terraform-mode.asd │ ├── lsp-config.lisp │ └── terraform-mode.lisp ├── typescript-mode │ ├── lem-typescript-mode.asd │ ├── lsp-config.lisp │ └── typescript-mode.lisp ├── vi-mode │ ├── README.md │ ├── binds.lisp │ ├── commands.lisp │ ├── commands │ │ └── utils.lisp │ ├── core.lisp │ ├── ex-command.lisp │ ├── ex-core.lisp │ ├── ex-parser.lisp │ ├── ex.lisp │ ├── jumplist.lisp │ ├── leader.lisp │ ├── lem-vi-mode.asd │ ├── modeline.lisp │ ├── options.lisp │ ├── rc-example.lisp │ ├── registers.lisp │ ├── special-binds.lisp │ ├── states.lisp │ ├── tests │ │ ├── commands.lisp │ │ ├── ex.lisp │ │ ├── jumplist.lisp │ │ ├── kbdmacro.lisp │ │ ├── motion.lisp │ │ ├── operator.lisp │ │ ├── options.lisp │ │ ├── registers.lisp │ │ ├── text-objects.lisp │ │ ├── utils.lisp │ │ └── visual.lisp │ ├── text-objects.lisp │ ├── utils.lisp │ ├── vi-mode.lisp │ ├── visual.lisp │ ├── window.lisp │ └── word.lisp ├── welcome │ ├── lem-welcome.asd │ └── welcome.lisp ├── xml-mode │ ├── lem-xml-mode.asd │ └── xml-mode.lisp └── yaml-mode │ ├── lem-yaml-mode.asd │ └── yaml-mode.lisp ├── flake.lock ├── flake.nix ├── frontends ├── fake-interface │ ├── fake-interface.lisp │ └── lem-fake-interface.asd ├── ncurses │ ├── attribute.lisp │ ├── cl-charms-pdcurseswin32.lisp │ ├── clipboard.lisp │ ├── config.lisp │ ├── drawing-object.lisp │ ├── input.lisp │ ├── key.lisp │ ├── lem-ncurses.asd │ ├── mainloop.lisp │ ├── ncurses.lisp │ ├── render.lisp │ ├── style.lisp │ ├── term.lisp │ └── view.lisp ├── pdcurses │ ├── lem-pdcurses.asd │ └── ncurses-pdcurseswin32.lisp ├── sdl2 │ ├── README.md │ ├── color-picker.lisp │ ├── display.lisp │ ├── drawing.lisp │ ├── font.lisp │ ├── graphics.lisp │ ├── icon-font.lisp │ ├── icon.lisp │ ├── image-buffer.lisp │ ├── keyboard.lisp │ ├── lem-sdl2.asd │ ├── log.lisp │ ├── main.lisp │ ├── mouse.lisp │ ├── platform.lisp │ ├── resource.lisp │ ├── resources │ │ ├── folder.png │ │ ├── fonts │ │ │ ├── FreeMono.ttf │ │ │ ├── NotoColorEmoji.ttf │ │ │ ├── NotoSansCJK-Bold.ttc │ │ │ ├── NotoSansCJK-Regular.ttc │ │ │ ├── NotoSansMono-Bold.ttf │ │ │ ├── NotoSansMono-Regular.ttf │ │ │ ├── all-the-icons.ttf │ │ │ ├── file-icons.ttf │ │ │ ├── fontawesome.ttf │ │ │ ├── material-design-icons.ttf │ │ │ └── octicons.ttf │ │ ├── icon.png │ │ └── open-folder.png │ ├── sdl2.lisp │ ├── text-surface-cache.lisp │ ├── tree.lisp │ ├── utils.lisp │ ├── view.lisp │ └── wm.lisp └── server │ ├── config.lisp │ ├── frontend │ ├── .gitignore │ ├── dist │ │ ├── assets │ │ │ └── index-DMdAQepA.js │ │ └── index.html │ ├── editor.js │ ├── index.html │ ├── jsonrpc.js │ ├── keyevent.js │ ├── main.js │ ├── package-lock.json │ └── package.json │ ├── jsonrpc-stdio-patch.lisp │ ├── lem-server.asd │ ├── main.lisp │ ├── mouse.lisp │ ├── utils.lisp │ └── view.lisp ├── lem-tests.asd ├── lem.asd ├── qlfile ├── qlfile.lock ├── roswell ├── lem-language-server.ros ├── lem-ncurses-ccl.ros ├── lem-ncurses.ros ├── lem-sdl2.ros └── lem.ros ├── screenshots ├── electron.png ├── pdcurses.png ├── sdl2.png └── terminal.png ├── scripts ├── build-ncurses.lisp ├── build-sdl2-ncurses.lisp ├── build-sdl2.lisp ├── build-server.lisp ├── generate-documentation-tests.lisp ├── install │ ├── lem.desktop │ ├── lem.ico │ └── lem.svg └── launch-tests.lisp ├── src ├── attribute.lisp ├── buffer-ext.lisp ├── buffer │ ├── buffer-list-manager.lisp │ ├── encodings.lisp │ ├── errors.lisp │ ├── file-utils.lisp │ ├── file.lisp │ ├── indent.lisp │ ├── internal │ │ ├── basic.lisp │ │ ├── buffer-insert.lisp │ │ ├── buffer.lisp │ │ ├── check-corruption.lisp │ │ ├── edit.lisp │ │ ├── editor-variables.lisp │ │ ├── mark.lisp │ │ ├── parse-partial-sexp.lisp │ │ ├── point.lisp │ │ ├── search.lisp │ │ ├── syntax-parser.lisp │ │ ├── syntax-predicates.lisp │ │ ├── syntax-scan.lisp │ │ ├── tmlanguage.lisp │ │ ├── undo.lisp │ │ └── var.lisp │ ├── interrupt.lisp │ ├── line.lisp │ ├── package.lisp │ └── syntax-table.lisp ├── clipboard.lisp ├── color-theme.lisp ├── command-advices.lisp ├── command.lisp ├── commands │ ├── buffer.lisp │ ├── edit.lisp │ ├── file.lisp │ ├── font.lisp │ ├── frame.lisp │ ├── help.lisp │ ├── mark.lisp │ ├── move.lisp │ ├── multiple-cursors.lisp │ ├── other.lisp │ ├── process.lisp │ ├── project.lisp │ ├── s-expression.lisp │ ├── window.lisp │ └── word.lisp ├── common │ ├── character │ │ ├── eastasian.lisp │ │ ├── icon.lisp │ │ ├── package.lisp │ │ └── string-width-utils.lisp │ ├── color.lisp │ ├── command.lisp │ ├── history.lisp │ ├── hooks.lisp │ ├── killring.lisp │ ├── queue.lisp │ ├── ring.lisp │ ├── socket.lisp │ ├── timer.lisp │ ├── utils.lisp │ └── var.lisp ├── completion.lisp ├── config.lisp ├── context-menu.lisp ├── cursors.lisp ├── defcommand.lisp ├── display │ ├── base.lisp │ ├── char-type.lisp │ ├── logical-line.lisp │ └── physical-line.lisp ├── echo.lisp ├── errors.lisp ├── event-queue.lisp ├── ext │ ├── abbrev.lisp │ ├── auto-save.lisp │ ├── button.lisp │ ├── completion-mode.lisp │ ├── context-menu.lisp │ ├── deepl.lisp │ ├── detective.lisp │ ├── directory-mode │ │ ├── attributes.lisp │ │ ├── commands.lisp │ │ ├── file.lisp │ │ ├── internal.lisp │ │ ├── keybinds.lisp │ │ ├── main.lisp │ │ └── mode.lisp │ ├── filer.lisp │ ├── frame-multiplexer.lisp │ ├── go-back.lisp │ ├── grep.lisp │ ├── gtags.lisp │ ├── hover.lisp │ ├── isearch.lisp │ ├── kbdmacro.lisp │ ├── language-mode-tools.lisp │ ├── language-mode.lisp │ ├── line-numbers.lisp │ ├── link.lisp │ ├── list-buffers.lisp │ ├── listener-mode.lisp │ ├── loading-spinner.lisp │ ├── markdown-buffer.lisp │ ├── multi-column-list.lisp │ ├── peek-source.lisp │ ├── popup-menu.lisp │ ├── popup-message.lisp │ ├── popup-window.lisp │ ├── prompt-window.lisp │ ├── read-only-sources.lisp │ ├── rectangle.lisp │ ├── showparen.lisp │ ├── tabbar.lisp │ ├── themes.lisp │ ├── thingatp.lisp │ ├── tmlanguage.lisp │ └── universal-argument.lisp ├── external-packages.lisp ├── file.lisp ├── format.lisp ├── frame.lisp ├── fundamental-mode.lisp ├── highlight-line.lisp ├── html-buffer.lisp ├── input.lisp ├── interface.lisp ├── internal-packages.lisp ├── interp.lisp ├── key.lisp ├── keymap.lisp ├── killring.lisp ├── lem.lisp ├── macros.lisp ├── mode.lisp ├── modeline.lisp ├── mouse.lisp ├── overlay.lisp ├── popup.lisp ├── prompt.lisp ├── region.lisp ├── save-excursion.lisp ├── site-init.lisp ├── streams.lisp ├── system-utils.lisp ├── system.lisp ├── typeout.lisp ├── ui │ └── theme-list.lisp ├── version.lisp └── window │ ├── floating-window.lisp │ ├── header-window.lisp │ ├── side-window.lisp │ ├── virtual-line.lisp │ ├── window-tree.lisp │ └── window.lisp └── tests ├── buffer-list-test.lisp ├── buffer └── internal.lisp ├── common ├── history.lisp ├── killring.lisp ├── ring.lisp └── timer.lisp ├── completion.lisp ├── cursors.lisp ├── e2e ├── frame-multiplexer.lisp └── vi-mode.lisp ├── file.lisp ├── interp.lisp ├── isearch.lisp ├── killring.lisp ├── language-server ├── micros-tests.lisp ├── tests.lisp └── utils.lisp ├── lisp-mode └── package-inferred-system.lisp ├── lisp-syntax ├── defstruct-to-defclass.lisp └── indent-test.lisp ├── popup-window.lisp ├── prompt.lisp ├── sample-code ├── LemScalaIndent.scala ├── defstruct-to-defclass.lisp ├── indent-sample.lisp ├── syntax-sample.lisp └── text.txt ├── scala-mode.lisp ├── self-insert-command.lisp ├── string-width-utils.lisp ├── syntax-test.lisp ├── thingatp.lisp └── utilities.lisp /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | open_collective: lem 2 | github: cxxxr 3 | -------------------------------------------------------------------------------- /.github/workflows/build-terminal-shared-object.yml: -------------------------------------------------------------------------------- 1 | name: Build terminal.so 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | runs-on: macos-latest 12 | 13 | steps: 14 | - name: Checkout repository 15 | uses: actions/checkout@v3 16 | 17 | - name: Install Homebrew 18 | run: | 19 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 20 | 21 | - name: Install vterm 22 | run: brew install libvterm 23 | 24 | - name: compile 25 | run: | 26 | cd extensions/terminal 27 | gcc terminal.c -I/opt/homebrew/include -L/opt/homebrew/lib -lvterm -o terminal.so -shared -fPIC 28 | mv terminal.so lib/macosx/arm64/terminal.so 29 | 30 | - name: Commit and push changes 31 | run: | 32 | git config --global user.name 'github-actions[bot]' 33 | git config --global user.email 'github-actions[bot]@users.noreply.github.com' 34 | git add . 35 | 36 | - name: Create Pull Request 37 | uses: peter-evans/create-pull-request@v6 38 | with: 39 | token: ${{ secrets.GITHUB_TOKEN }} 40 | commit-message: Add terminal.so 41 | branch: update-terminal-so-macosx-arm64 42 | title: Add terminal.so file 43 | body: Update terminal.so on macosx/arm64 44 | -------------------------------------------------------------------------------- /.github/workflows/generate-document.yml: -------------------------------------------------------------------------------- 1 | name: Generate document 2 | 3 | on: 4 | push: 5 | branches: [ 'main' ] 6 | workflow_dispatch: 7 | branches: [ '*' ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Install Roswell 16 | env: 17 | LISP: ${{ matrix.lisp }} 18 | run: | 19 | curl -L https://raw.githubusercontent.com/roswell/roswell/v22.12.14.113/scripts/install-for-ci.sh | sh 20 | - name: Generate document and create pull request 21 | env: 22 | GH_TOKEN: ${{ github.token }} 23 | run: | 24 | set -ex 25 | 26 | ros config set dynamic-space-size 2048 27 | curl -L https://qlot.tech/installer | bash 28 | export PATH="/home/runner/.qlot/bin:$PATH" 29 | qlot install 30 | 31 | document_file=docs/default-keybindings.md 32 | 33 | qlot exec ros -s lem -s lem/extensions -e "(lem-documentation-mode:generate-markdown-file \"${document_file}\" :command)" 34 | 35 | if [ -z "$(git diff ${document_file})" ]; then 36 | exit 0 37 | fi 38 | 39 | git config --global user.email "github-actions[bot]@users.noreply.github.com" 40 | git config --global user.name "github-actions[bot]" 41 | 42 | branch_name="update-docs-$(date '+%Y%m%d-%H%M%S')" 43 | git checkout -b $branch_name 44 | git add ${document_file} 45 | git commit -m "update ${document_file}" 46 | git push origin $branch_name 47 | 48 | gh pr create -B main -t "update ${document_file} $(date '+%Y%m%d-%H%M%S')" -b '' 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | DEBUG 2 | *.fasl 3 | node_modules 4 | roswell/lem-ncurses 5 | *~ 6 | 7 | contrib/Makefile.am 8 | Makefile.in 9 | compile 10 | configure 11 | config.status 12 | config.log 13 | aclocal.m4 14 | autom4te.cache 15 | install-sh 16 | missing 17 | bin/ 18 | system-index.txt 19 | 20 | lem-icon.svg 21 | lem-ncurses.desktop 22 | 23 | .DS_Store 24 | 25 | GIT_IGNORE.* 26 | 27 | lem 28 | lem-ncurses 29 | lem-server 30 | 31 | *.abcl 32 | build/* 33 | 34 | *.lx64fsl 35 | .qlot 36 | /systems/ 37 | 38 | /result 39 | 40 | TODO 41 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | WORKDIR /app 4 | 5 | COPY . . 6 | 7 | RUN apk add --no-cache curl bash build-base ncurses-dev sbcl git xdg-utils 8 | 9 | RUN curl -o quicklisp.lisp https://beta.quicklisp.org/quicklisp.lisp 10 | RUN sbcl --noinform --no-userinit --no-sysinit --non-interactive --load quicklisp.lisp --eval "(quicklisp-quickstart:install)" --eval "(ql-util:without-prompting (ql:add-to-init-file))" 11 | 12 | RUN curl -L https://qlot.tech/installer | bash 13 | 14 | RUN qlot install && \ 15 | qlot exec sbcl --noinform --load scripts/build-ncurses.lisp 16 | 17 | ENTRYPOINT qlot exec sbcl --noinform --eval "(ql:quickload :lem-ncurses)" --eval "(lem:lem)" --quit 18 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 cxxxr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /contrib/README.md: -------------------------------------------------------------------------------- 1 | # contribs for lem 2 | 3 | Files in this directroy are libraries which aren't loaded by default. 4 | 5 | ## How to try contrib 6 | 7 | ``` 8 | M-x load-library 9 | ``` 10 | 11 | you can see completion by tab key. 12 | 13 | ## If you want the contrib after restart lem 14 | 15 | ``` 16 | M-x site-init-add-dependency 17 | ``` 18 | 19 | And choose which library to install. 20 | 21 | then 22 | 23 | ``` 24 | #ros install lem 25 | ``` 26 | 27 | for uninstall. 28 | 29 | ``` 30 | M-x site-init-remove-dependency 31 | ``` 32 | 33 | then 34 | 35 | ``` 36 | #ros install lem 37 | ``` 38 | -------------------------------------------------------------------------------- /contrib/bracket-paren-mode/bracket-paren-mode.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-bracket-paren-mode 2 | (:use :cl :lem) 3 | (:export :bracket-paren-mode)) 4 | 5 | (in-package :lem-bracket-paren-mode) 6 | 7 | (define-minor-mode bracket-paren-mode 8 | (:name "bracket-paren-mode" 9 | :keymap *bracket-paren-keymap*)) 10 | 11 | (define-key *bracket-paren-keymap* ")" 'insert-closed-paren) 12 | (define-key *bracket-paren-keymap* "}" 'insert-closed-paren) 13 | (define-key *bracket-paren-keymap* "]" 'insert-closed-paren) 14 | 15 | (defun get-closed-paren-list () 16 | (mapcar #'cdr 17 | (syntax-table-paren-pairs (current-syntax)))) 18 | 19 | (define-command insert-closed-paren () () 20 | (let ((c (insertion-key-p (last-read-key-sequence)))) 21 | (flet ((check-open-paren () 22 | (scan-lists (copy-point (current-point) :temporary) -1 0 t)) 23 | (cancel-insert () 24 | (character-offset (current-point) -1) 25 | (delete-character (current-point)))) 26 | (insert-character (current-point) c) 27 | (when (and (syntax-closed-paren-char-p c) 28 | (not (check-open-paren))) 29 | (unless (loop for closed-paren in (get-closed-paren-list) 30 | do 31 | 32 | (cancel-insert) 33 | (insert-character (current-point) closed-paren) 34 | (if (check-open-paren) 35 | (return t))) 36 | (cancel-insert) 37 | (insert-character (current-point) c)))))) 38 | -------------------------------------------------------------------------------- /contrib/bracket-paren-mode/lem-bracket-paren-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-bracket-paren-mode" 2 | :serial t 3 | :depends-on ("lem") 4 | :components ((:file "bracket-paren-mode"))) 5 | -------------------------------------------------------------------------------- /contrib/calc-mode/lem-calc-mode.asd: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (defsystem "lem-calc-mode" 3 | :depends-on("lem") 4 | :class :package-inferred-system 5 | :components((:file "main")) 6 | :author "SANO Masatoshi" 7 | :mailto "snmsts@gmail.com") 8 | -------------------------------------------------------------------------------- /contrib/calc-mode/project.lisp: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (let ((data '(("asd" "lem-calc-mode")))) 3 | (dolist (n (assoc "asd" data :test 'equal)) 4 | (funcall (read-from-string "asdf:load-asd") 5 | (make-pathname :defaults *load-pathname* :name n :type "asd")))) 6 | -------------------------------------------------------------------------------- /contrib/fbar/Readme.md: -------------------------------------------------------------------------------- 1 | # FBAR 2 | 3 | FBAR is a minimal file-tree-bar for Lem editor. 4 | 5 | FBAR permits a fast and easy, as well as a persistent, listing of files and directories, in a pop-up window on the left side of the screen. 6 | 7 | ## Quickstart 8 | 9 | Load FBAR from your `~/.lem/init.lisp` file with something like: 10 | ``` 11 | (load-library "fbar") 12 | (lem-fbar:fbar (truename "~/path/to/projects/")) 13 | ``` 14 | 15 | A new keybinding `` is added to trigger the fbar; `` cancels it. 16 | 17 | ``, `` as well as vi `` and `` keys navigate up and down. Hitting `` on a directory opens (or closes) it; on a file `` attempts to load the file. 18 | -------------------------------------------------------------------------------- /contrib/fbar/lem-fbar.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-fbar" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "fbar"))) 5 | -------------------------------------------------------------------------------- /contrib/google-translate/README.md: -------------------------------------------------------------------------------- 1 | # google-translate 2 | 3 | ## setup API 4 | 5 | in ``~/.lem/init.lisp`` 6 | 7 | ``` 8 | (defparameter lem-user::*google-api-key* "your api key") 9 | ``` 10 | 11 | or setenv GOOGLEAPI 12 | 13 | ``` 14 | (defparameter lem-user::*google-api-key* (uiop:getenv "GOOGLEAPI")) 15 | ``` 16 | 17 | ## load-library 18 | 19 | ``` 20 | M-x load-library 21 | google-translate 22 | ``` 23 | 24 | ## how to translate 25 | 26 | select region then 27 | 28 | ``` 29 | M-x popup-google-translate 30 | ``` 31 | -------------------------------------------------------------------------------- /contrib/google-translate/lem-google-translate.asd: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (defsystem "lem-google-translate" 3 | :depends-on("lem" 4 | "translate-client") 5 | :class :package-inferred-system 6 | :components((:file "main")) 7 | :author "SANO Masatoshi" 8 | :mailto "snmsts@gmail.com") 9 | -------------------------------------------------------------------------------- /contrib/google-translate/main.lisp: -------------------------------------------------------------------------------- 1 | (uiop/package:define-package :lem-google-translate/main (:use :cl :lem)) 2 | (in-package :lem-google-translate/main) 3 | ;;;don't edit above 4 | (defvar lem-user::*google-api-key* nil) 5 | 6 | (define-command popup-google-translate (start end) (:region) 7 | (display-popup-message 8 | (translate-client:translate 9 | (points-to-string start end) 10 | :target :ja 11 | :api-key lem-user::*google-api-key*))) -------------------------------------------------------------------------------- /contrib/google-translate/project.lisp: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (let ((data '(("asd" "lem-google-translate")))) 3 | (dolist (n (assoc "asd" data :test 'equal)) 4 | (funcall (read-from-string "asdf:load-asd") 5 | (make-pathname :defaults *load-pathname* :name n :type "asd")))) 6 | -------------------------------------------------------------------------------- /contrib/lem-contrib.asd: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (DEFSYSTEM "lem-contrib") 3 | -------------------------------------------------------------------------------- /contrib/migemo/lem-migemo.asd: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (defsystem "lem-migemo" 3 | :class :package-inferred-system 4 | :components((:file "main")) 5 | :depends-on("lem" 6 | :cl-migemo)) 7 | #+roswell(UNLESS (ASDF/SYSTEM:FIND-SYSTEM "cl-migemo" NIL) 8 | (UIOP/PACKAGE:SYMBOL-CALL "ROSWELL" "ROSWELL" 9 | '("install" "snmsts/cl-migemo"))) 10 | -------------------------------------------------------------------------------- /contrib/migemo/main.lisp: -------------------------------------------------------------------------------- 1 | (uiop/package:define-package :lem-migemo/main (:use :cl :lem)) 2 | (in-package :lem-migemo/main) 3 | ;;;don't edit above 4 | 5 | (defun search-forward-migemo (point query &optional limit-point) 6 | (search-forward-regexp point (cl-migemo:query query) limit-point)) 7 | 8 | (defun search-backward-migemo (point query &optional limit-point) 9 | (search-backward-regexp point (cl-migemo:query query) limit-point)) 10 | 11 | (define-command isearch-forward-migemo (&optional prompt) () 12 | (lem/isearch::isearch-start (or prompt "ISearch Migemo: ") 13 | (lem/isearch::make-add-char-callback #'search-forward-migemo) 14 | #'search-forward-migemo 15 | #'search-backward-migemo 16 | "")) 17 | 18 | (define-command isearch-backward-migemo (&optional prompt) () 19 | (lem/isearch::isearch-start (or prompt "ISearch Migemo: ") 20 | (lem/isearch::make-add-char-callback #'search-backward-migemo) 21 | #'search-forward-migemo 22 | #'search-backward-migemo 23 | "")) 24 | 25 | (define-minor-mode migemo-mode (:global t 26 | :keymap *migemo-mode-keymap* 27 | :name "migemo")) 28 | 29 | (define-key *migemo-mode-keymap* 'lem/isearch:isearch-forward 'isearch-forward-migemo) 30 | (define-key *migemo-mode-keymap* 'lem/isearch:isearch-backward 'isearch-backward-migemo) 31 | -------------------------------------------------------------------------------- /contrib/migemo/project.lisp: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (let ((data '(("asd" "lem-migemo")))) 3 | (dolist (n (assoc "asd" data :test 'equal)) 4 | (funcall (read-from-string "asdf:load-asd") 5 | (make-pathname :defaults *load-pathname* :name n :type "asd")))) 6 | -------------------------------------------------------------------------------- /contrib/modeline-battery/lem-modeline-battery.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-modeline-battery" 2 | :depends-on ("trivial-battery" "lem") 3 | :serial t 4 | :components ((:file "main"))) 5 | -------------------------------------------------------------------------------- /contrib/modeline-battery/main.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-modeline-battery 2 | (:use :cl :lem) 3 | (:export :enable 4 | :disable)) 5 | (in-package :lem-modeline-battery) 6 | 7 | (defvar *last-time* nil) 8 | (defvar *cache-values* nil) 9 | (defvar *interval-second* 10) 10 | 11 | (defun update-cache-p () 12 | (let ((time (get-universal-time))) 13 | (when (or (null *last-time*) 14 | (<= *interval-second* (- time *last-time*))) 15 | (setf *last-time* time) 16 | t))) 17 | 18 | (defun battery (window) 19 | (declare (ignore window)) 20 | (when (update-cache-p) 21 | (alexandria:when-let ((info (first (trivial-battery:battery-info)))) 22 | (let ((percentage (alexandria:assoc-value info "percentage" :test #'equal)) 23 | (charging (alexandria:assoc-value info "charging" :test #'equal))) 24 | (setf *cache-values* 25 | (if charging 26 | (list (format nil "[~D% AC] " percentage) nil :right) 27 | (list (format nil "[~D% BAT] " percentage) nil :right)))))) 28 | (apply #'values *cache-values*)) 29 | 30 | (defun enable () 31 | (modeline-add-status-list 'battery)) 32 | 33 | (defun disable () 34 | (modeline-remove-status-list 'battery)) 35 | -------------------------------------------------------------------------------- /contrib/mouse-sgr1006/lem-mouse-sgr1006.asd: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (defsystem "lem-mouse-sgr1006" 3 | :depends-on("lem" "lem-ncurses") 4 | :class :package-inferred-system 5 | :components((:file "main"))) 6 | -------------------------------------------------------------------------------- /contrib/mouse-sgr1006/project.lisp: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (let ((data '(("asd" "lem-mouse-sgr1006")))) 3 | (dolist (n (assoc "asd" data :test 'equal)) 4 | (funcall (read-from-string "asdf:load-asd") 5 | (make-pathname :defaults *load-pathname* :name n :type "asd")))) 6 | -------------------------------------------------------------------------------- /contrib/ollama/README.md: -------------------------------------------------------------------------------- 1 | # lem-ollama 2 | 3 | A client for interacting with LLMs 4 | 5 | ## Setup 6 | 7 | in ``~/.config/lem/init.lisp`` 8 | 9 | If you aren't running Ollama on localhost, specify a server: 10 | 11 | ```lisp 12 | (setf lem-ollama:*host* "your.machine:1234") 13 | ``` 14 | 15 | You can also specify the model used: 16 | 17 | ```lisp 18 | (setf lem-ollama:*model* "llama2") 19 | ``` 20 | 21 | ## run-ollama 22 | 23 | Start an listener-mode buffer talking to the LLM. 24 | 25 | ## ollama-prompt 26 | 27 | Send a prompt and stream the response into a temp buffer. 28 | 29 | ## ollama-close 30 | 31 | Close the current response stream, bound to C-c C-c by default. -------------------------------------------------------------------------------- /contrib/ollama/lem-ollama.asd: -------------------------------------------------------------------------------- 1 | (asdf:defsystem "lem-ollama" 2 | :author "garlic0x1" 3 | :description "An ollama client for Lem." 4 | :license "MIT" 5 | :class :package-inferred-system 6 | :depends-on (:lem :alexandria :bordeaux-threads :dexador :cl-json :chunga) 7 | :components ((:file "ollama") 8 | (:file "listener"))) 9 | -------------------------------------------------------------------------------- /contrib/ollama/project.lisp: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (let ((data '(("asd" "lem-ollama")))) 3 | (dolist (n (assoc "asd" data :test 'equal)) 4 | (funcall (read-from-string "asdf:load-asd") 5 | (make-pathname :defaults *load-pathname* :name n :type "asd")))) 6 | -------------------------------------------------------------------------------- /contrib/overwrite-mode/lem-overwrite-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-overwrite-mode" 2 | :serial t 3 | :depends-on ("lem") 4 | :components ((:file "overwrite-mode"))) 5 | 6 | -------------------------------------------------------------------------------- /contrib/overwrite-mode/overwrite-mode.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-overwrite-mode 2 | (:use :cl :lem)) 3 | (in-package :lem-overwrite-mode) 4 | 5 | (define-key *global-keymap* 6 | "Insert" 'overwrite-mode) 7 | 8 | (define-minor-mode overwrite-mode 9 | (:name "Overwrite" 10 | :global nil 11 | :enable-hook 'enable 12 | :disable-hook 'disable)) 13 | 14 | (defun hook-function (char) 15 | (declare (ignore char)) 16 | (unless (end-line-p (current-point)) 17 | (delete-next-char))) 18 | 19 | (defun enable () 20 | (add-hook (variable-value 'self-insert-before-hook) 21 | 'hook-function)) 22 | 23 | (defun disable () 24 | (remove-hook (variable-value 'self-insert-before-hook) 25 | 'hook-function)) 26 | -------------------------------------------------------------------------------- /contrib/selection-mode/lem-selection-mode.asd: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (defsystem "lem-selection-mode" 3 | :depends-on("lem") 4 | :class :package-inferred-system 5 | :components((:file "selection-mode")) 6 | :author "SANO Masatoshi" 7 | :mailto "snmsts@gmail.com") 8 | -------------------------------------------------------------------------------- /contrib/selection-mode/project.lisp: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (let ((data '(("asd" "lem-selection-mode")))) 3 | (dolist (n (assoc "asd" data :test 'equal)) 4 | (funcall (read-from-string "asdf:load-asd") 5 | (make-pathname :defaults *load-pathname* :name n :type "asd")))) 6 | -------------------------------------------------------------------------------- /contrib/tetris/lem-tetris.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-tetris" 2 | :serial t 3 | :depends-on ("lem") 4 | :components ((:file "tetris"))) 5 | -------------------------------------------------------------------------------- /contrib/trailing-spaces/lem-trailing-spaces.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-trailing-spaces" 2 | :serial t 3 | :depends-on ("lem") 4 | :components ((:file "trailing-spaces"))) 5 | -------------------------------------------------------------------------------- /contrib/trailing-spaces/trailing-spaces.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-trailing-spaces 2 | (:use :cl :lem) 3 | (:export)) 4 | (in-package :lem-trailing-spaces) 5 | 6 | (define-attribute space-attribute 7 | (t :background "cyan")) 8 | 9 | (defvar *space-attribute* (make-attribute :background "cyan")) 10 | 11 | (define-minor-mode trailing-spaces 12 | (:name "Trailing Spaces" 13 | :global t 14 | :enable-hook 'enable 15 | :disable-hook 'disable)) 16 | 17 | (defun clear-space-attribute (start end) 18 | (with-point ((p start) 19 | (p2 start)) 20 | (loop :while (point< p end) 21 | :do (when (eq 'space-attribute (text-property-at p :attribute)) 22 | (remove-text-property p (character-offset (move-point p2 p) 1) :attribute)) 23 | (unless (character-offset p 1) 24 | (return))))) 25 | 26 | (defun scan-trailing-spaces (start end) 27 | (unless (lem-core:not-switchable-buffer-p (lem:current-buffer)) 28 | (with-point ((p1 start) 29 | (p2 start) 30 | (end end)) 31 | (line-start p1) 32 | (line-end end) 33 | (clear-space-attribute p1 end) 34 | (loop :while (point< p1 end) 35 | :do (line-end p1) 36 | (move-point p2 p1) 37 | (skip-whitespace-backward p1 t) 38 | (put-text-property p1 p2 :attribute 'space-attribute) 39 | (unless (line-offset p1 1) 40 | (return)))))) 41 | 42 | (defun enable () 43 | (add-hook (variable-value 'after-syntax-scan-hook :global) 44 | 'scan-trailing-spaces)) 45 | 46 | (defun disable () 47 | (remove-hook (variable-value 'after-syntax-scan-hook :global) 48 | 'scan-trailing-spaces)) 49 | -------------------------------------------------------------------------------- /contrib/version-up/lem-version-up.asd: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (defsystem "lem-version-up" 3 | :depends-on("lem" "cl-ppcre") 4 | :class :package-inferred-system 5 | :components((:file "version")) 6 | :author "SANO Masatoshi" 7 | :mailto "snmsts@gmail.com") 8 | -------------------------------------------------------------------------------- /contrib/version-up/project.lisp: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (let ((data '(("asd" "lem-version-up")))) 3 | (dolist (n (assoc "asd" data :test 'equal)) 4 | (funcall (read-from-string "asdf:load-asd") 5 | (make-pathname :defaults *load-pathname* :name n :type "asd")))) 6 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | (import (let lock = builtins.fromJSON (builtins.readFile ./flake.lock); 2 | in fetchTarball { 3 | url = 4 | lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; 5 | sha256 = lock.nodes.flake-compat.locked.narHash; 6 | }) { src = ./.; }).defaultNix 7 | -------------------------------------------------------------------------------- /docker/Dockerfile-rpc: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | RUN apk add --no-cache curl bash build-base sbcl git docker 4 | 5 | WORKDIR /work 6 | RUN curl -o quicklisp.lisp https://beta.quicklisp.org/quicklisp.lisp 7 | RUN sbcl --noinform --no-userinit --no-sysinit --non-interactive --load quicklisp.lisp --eval "(quicklisp-quickstart:install)" --eval "(ql-util:without-prompting (ql:add-to-init-file))" 8 | 9 | WORKDIR /work 10 | RUN git clone https://github.com/lem-project/micros.git 11 | RUN git clone https://github.com/lem-project/lem-mailbox.git 12 | RUN git clone https://github.com/lem-project/lem-base16-themes.git 13 | RUN git clone https://github.com/lem-project/async-process.git 14 | RUN git clone https://github.com/cxxxr/sblint.git 15 | RUN git clone https://github.com/fukamachi/rove.git 16 | RUN git clone https://github.com/lem-project/cl-sdl2.git 17 | RUN git clone https://github.com/lem-project/cl-sdl2-ttf.git 18 | RUN git clone https://github.com/lem-project/cl-sdl2-image.git 19 | RUN git clone https://github.com/cxxxr/jsonrpc.git 20 | 21 | WORKDIR /work/lem-rpc 22 | COPY . . 23 | 24 | RUN mkdir -p ~/.config/common-lisp/ 25 | RUN echo "(:source-registry (:tree \"/work/\") :inherit-configuration)" > ~/.config/common-lisp/source-registry.conf 26 | 27 | RUN sbcl --dynamic-space-size 4GB --disable-ldb --load scripts/build-rpc.lisp 28 | 29 | 30 | RUN chmod 755 /work/lem-rpc/lem-rpc 31 | 32 | RUN adduser -D user 33 | USER user 34 | WORKDIR /home/user 35 | 36 | RUN sbcl --load /work/quicklisp.lisp --eval "(quicklisp-quickstart:install)" --eval "(ql-util:without-prompting (ql:add-to-init-file))" 37 | 38 | ENTRYPOINT ["/work/lem-rpc/docker/entrypoint.sh"] 39 | -------------------------------------------------------------------------------- /docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | 3 | /work/lem-rpc/lem-rpc --mode websocket --port 50000 --host 0.0.0.0 4 | -------------------------------------------------------------------------------- /extensions/asciidoc-mode/lem-asciidoc-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-asciidoc-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "asciidoc-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/asm-mode/lem-asm-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-asm-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "asm-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/c-mode/format.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-c-mode/format 2 | (:use :cl :lem) 3 | (:import-from #:alexandria-2 #:curry #:line-up-last) 4 | (:export #:clang-format) 5 | #+sbcl 6 | (:lock t)) 7 | (in-package :lem-c-mode/format) 8 | 9 | (defun walk-to-root (path) 10 | "Walk up the file tree collecting directories." 11 | (let ((dir (uiop:pathname-directory-pathname path))) 12 | (if (equal #P"/" dir) 13 | (list dir) 14 | (cons dir (walk-to-root (uiop:pathname-parent-directory-pathname dir)))))) 15 | 16 | (defun file-in-path (file path) 17 | "Test if a file exists in a directory path." 18 | (uiop:file-exists-p (merge-pathnames path file))) 19 | 20 | (defun clang-spec (path) 21 | "Walk up file tree looking for .clang-format spec." 22 | (line-up-last 23 | (walk-to-root path) 24 | (mapcar (curry #'file-in-path ".clang-format")) 25 | (find-if #'identity))) 26 | 27 | (defun clang-format (buf) 28 | "Format a C buffer with clang-format." 29 | (let ((file (buffer-filename buf))) 30 | (uiop:run-program 31 | (format nil "clang-format --style=file:~a -i ~a" (clang-spec file) file) 32 | :ignore-error-status t)) 33 | (revert-buffer t)) 34 | -------------------------------------------------------------------------------- /extensions/c-mode/lem-c-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-c-mode" 2 | :depends-on ("lem" "lem-lisp-mode") 3 | :serial t 4 | :components ((:file "grammar") 5 | (:file "format") 6 | (:file "c-mode"))) 7 | -------------------------------------------------------------------------------- /extensions/coalton-mode/lem-coalton-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-coalton-mode" 2 | :depends-on ("lem" 3 | "lem-lisp-mode" 4 | "micros") 5 | :components 6 | ((:file "coalton-mode"))) 7 | -------------------------------------------------------------------------------- /extensions/color-preview/lem-color-preview.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-color-preview" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "color-preview"))) 5 | -------------------------------------------------------------------------------- /extensions/copilot/install.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-copilot/install 2 | (:use :cl :lem) 3 | (:local-nicknames (:client :lem-copilot/client) 4 | (:logger :lem-copilot/logger) 5 | (:copilot :lem-copilot)) 6 | (:export :copilot-install-server)) 7 | (in-package :lem-copilot/install) 8 | 9 | (define-command copilot-install-server () () 10 | (let* ((buffer (make-buffer "*copilot-install-server*")) 11 | (command (list "npm" 12 | "-g" 13 | "--prefix" 14 | (namestring (copilot::copilot-root)) 15 | "install" 16 | "copilot-node-server@1.40.0"))) 17 | (erase-buffer buffer) 18 | (pop-to-buffer buffer) 19 | (with-point ((point (buffer-point buffer) :left-inserting)) 20 | (with-open-stream (output (make-editor-output-stream point)) 21 | (format output "~{~A ~}~%" command) 22 | (redraw-display) 23 | (uiop:run-program command 24 | :output output 25 | :error-output output))))) 26 | -------------------------------------------------------------------------------- /extensions/copilot/lem-copilot.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-copilot" 2 | :depends-on ("lem" "lem-lsp-mode") 3 | :components ((:file "utils") 4 | (:file "logger") 5 | (:file "client") 6 | (:file "copilot") 7 | (:file "install") 8 | (:file "sign-in") 9 | (:file "languages") 10 | (:file "test-commands"))) 11 | -------------------------------------------------------------------------------- /extensions/copilot/logger.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-copilot/logger 2 | (:use :cl) 3 | (:local-nicknames (:ring :lem/common/ring)) 4 | (:export :do-log 5 | :write-log)) 6 | (in-package :lem-copilot/logger) 7 | 8 | (defvar *logs* (ring:make-ring 1000)) 9 | (defvar *log-lock* (bt2:make-lock :name "copilot log lock")) 10 | 11 | (defun do-log (output) 12 | (bt2:with-lock-held (*log-lock*) 13 | (ring:ring-push *logs* output))) 14 | 15 | (defun write-log (stream) 16 | (bt2:with-lock-held (*log-lock*) 17 | (loop :for i :downfrom (1- (ring:ring-length *logs*)) :to 0 18 | :for log := (ring:ring-ref *logs* i) 19 | :do (write-line log stream)))) 20 | -------------------------------------------------------------------------------- /extensions/copilot/test-commands.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-copilot/test-commands 2 | (:use :cl :lem :lem-copilot/utils) 3 | (:local-nicknames (:client :lem-copilot/client) 4 | (:logger :lem-copilot/logger) 5 | (:copilot :lem-copilot))) 6 | (in-package :lem-copilot/test-commands) 7 | 8 | (define-command test/copilot-document () () 9 | (let ((response (client:request (copilot::client) 10 | "testing/getDocument" 11 | (hash "uri" (copilot::buffer-uri (current-buffer)))))) 12 | (show-message (pretty-json response)) 13 | (assert (equal (gethash "text" response) 14 | (buffer-text (current-buffer)))))) 15 | 16 | (define-command test/copilot-log () () 17 | (let* ((buffer (make-buffer "*copilot-log*" :enable-undo-p nil))) 18 | (erase-buffer buffer) 19 | (with-open-stream (stream (make-buffer-output-stream (buffer-point buffer))) 20 | (logger:write-log stream)) 21 | (pop-to-buffer buffer))) 22 | -------------------------------------------------------------------------------- /extensions/copilot/utils.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-copilot/utils 2 | (:use :cl) 3 | (:export :hash 4 | :pretty-json)) 5 | (in-package :lem-copilot/utils) 6 | 7 | (defun hash (&rest args) 8 | (alexandria:plist-hash-table args :test 'equal)) 9 | 10 | (defun pretty-json (params) 11 | (with-output-to-string (stream) 12 | (yason:encode params (yason:make-json-output-stream stream)))) 13 | -------------------------------------------------------------------------------- /extensions/css-mode/lem-css-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-css-mode" 2 | :depends-on ("lem" 3 | "cl-ppcre") 4 | :serial t 5 | :components ((:file "css-mode"))) 6 | -------------------------------------------------------------------------------- /extensions/dart-mode/lem-dart-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-dart-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "dart-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/documentation-mode/documentation-mode.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-documentation-mode 2 | (:use :cl 3 | :lem 4 | :lem-documentation-mode/internal) 5 | (:export :documentation-mode 6 | :*documentation-mode-keymap* 7 | :documentation-select 8 | :generate-markdown-file)) 9 | (in-package :lem-documentation-mode) 10 | 11 | (define-major-mode documentation-mode () 12 | (:name "Documentation" 13 | :keymap *documentation-mode-keymap*) 14 | (setf (variable-value 'line-wrap :buffer (current-buffer)) nil) 15 | (setf (buffer-read-only-p (current-buffer)) t)) 16 | 17 | (define-key *documentation-mode-keymap* "Return" 'documentation-select) 18 | 19 | (define-command documentation-select () () 20 | (select-command-at-point (current-point))) 21 | 22 | ;; TODO: Override describe-bindings when implementation to display all key bindings is complete. 23 | (define-command documentation-describe-bindings () () 24 | (let ((buffer (generate-buffer "*Documentation describe-bindings*"))) 25 | (change-buffer-mode buffer 'documentation-mode) 26 | (switch-to-buffer buffer))) 27 | -------------------------------------------------------------------------------- /extensions/documentation-mode/lem-documentation-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-documentation-mode" 2 | :depends-on ("lem" "lem-lisp-syntax") 3 | :serial t 4 | :components ((:file "utils") 5 | (:file "internal") 6 | (:file "documentation-mode"))) 7 | -------------------------------------------------------------------------------- /extensions/documentation-mode/utils.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-documentation-mode/utils 2 | (:use :cl) 3 | (:export :collect-global-command-packages 4 | :collect-commands-in-package)) 5 | (in-package :lem-documentation-mode/utils) 6 | 7 | (defun extract-defpackage-name (form) 8 | (assert (and (consp form) 9 | (member (first form) '(defpackage uiop:define-package)))) 10 | (second form)) 11 | 12 | (defun collect-global-command-packages () 13 | (loop :for component :in (asdf:component-children (asdf:find-component :lem "commands")) 14 | :collect (find-package 15 | (extract-defpackage-name 16 | (uiop:read-file-form 17 | (asdf:component-pathname component)))))) 18 | 19 | #+sbcl 20 | (defun sort-by-file-location (commands) 21 | (sort commands 22 | #'< 23 | :key (lambda (command) 24 | (sb-c:definition-source-location-toplevel-form-number 25 | (lem-core::command-source-location command))))) 26 | 27 | (defun collect-commands-in-package (package) 28 | (let ((commands '())) 29 | (do-external-symbols (sym package) 30 | (let ((command (lem:get-command sym))) 31 | (when command 32 | (push command commands)))) 33 | #+sbcl 34 | (sort-by-file-location commands) 35 | #-sbcl 36 | commands)) 37 | -------------------------------------------------------------------------------- /extensions/dot-mode/lem-dot-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-dot-mode" 2 | :depends-on ("lem" 3 | "cl-ppcre") 4 | :serial t 5 | :components ((:file "dot-mode"))) 6 | -------------------------------------------------------------------------------- /extensions/elisp-mode/lem-elisp-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-elisp-mode" 2 | :depends-on ("lem" 3 | "jsonrpc" 4 | "lem-lisp-mode" 5 | #+#.(cl:if (asdf:find-system :async-process cl:nil) '(and) '(or)) "lem-process") 6 | :serial t 7 | :components ((:file "rpc") 8 | (:file "elisp-mode") 9 | (:file "run-elisp"))) -------------------------------------------------------------------------------- /extensions/elixir-mode/lem-elixir-mode.asd: -------------------------------------------------------------------------------- 1 | 2 | (defsystem "lem-elixir-mode" 3 | :depends-on ("lem" 4 | "lem-lsp-mode" 5 | #+#.(cl:if (asdf:find-system :async-process cl:nil) '(and) '(or)) "lem-process") 6 | :serial t 7 | :components ((:file "elixir-mode") 8 | (:file "lsp-config") 9 | #+#.(cl:if (asdf:find-system :async-process cl:nil) '(and) '(or)) 10 | (:file "run-elixir"))) 11 | -------------------------------------------------------------------------------- /extensions/elixir-mode/lsp-config.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-elixir-mode/lsp-config 2 | (:use :cl :lem-lsp-mode :lem-lsp-base/type)) 3 | 4 | (in-package :lem-elixir-mode/lsp-config) 5 | 6 | (define-language-spec (elixir-spec lem-elixir-mode:elixir-mode) 7 | :language-id "elixir" 8 | :root-uri-patterns '("mix.exs") 9 | :command '("sh" "language_server.sh") 10 | :install-command "" 11 | :readme-url "https://github.com/elixir-lsp/elixir-ls" 12 | :connection-mode :stdio) 13 | -------------------------------------------------------------------------------- /extensions/encodings/encodings-table/8bit.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-encodings-table/8bit 2 | (:use :cl) 3 | (:export :generate-table)) 4 | (in-package :lem-encodings-table/8bit) 5 | 6 | (defun map-bytes (fun) 7 | (loop for c from #x00 to #xff 8 | do (funcall fun c))) 9 | 10 | (defun generate-table (file code) 11 | (with-open-file (out file 12 | :direction :output 13 | :if-exists :supersede) 14 | (map-bytes 15 | (lambda (&rest x) 16 | (ignore-errors 17 | (let ((string (iconv:iconv-to-string code (coerce x 'simple-vector)))) 18 | (format out "0x~{~2,'0x~} U+~4,'0x ~A~A~%" 19 | x 20 | (char-code (aref string 0)) 21 | (cond ((equal string (format nil "~%")) "\\n") 22 | ((equal string " ") "SPC") 23 | (t string)) 24 | (if (ignore-errors 25 | (equal x (coerce (iconv:iconv-from-string code string) 'list))) 26 | "" 27 | (format nil " 0x~{~2,'0x~}" (coerce (iconv:iconv-from-string code string) 'list)))))))))) 28 | -------------------------------------------------------------------------------- /extensions/encodings/encodings-table/lem-encodings-table.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-encodings-table" 2 | :depends-on ("iconv") 3 | :class :package-inferred-system 4 | :components ((:file "8bit") 5 | (:file "euc") 6 | (:file "sjis") 7 | (:file "main"))) 8 | -------------------------------------------------------------------------------- /extensions/encodings/encodings-table/sjis.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-encodings-table/sjis 2 | (:use :cl) 3 | (:export :generate-table)) 4 | (in-package :lem-encodings-table/sjis) 5 | 6 | (defun map-bytes (fun) 7 | "from https://en.wikipedia.org/wiki/Shift_JIS#Shift_JISx0213_and_Shift_JIS-2004" 8 | (loop for c from #x00 to #x7f 9 | do (funcall fun c)) 10 | (loop for c from #xa1 to #xdf 11 | do (funcall fun c)) 12 | (loop for c1 from #x81 to #x9f 13 | do (loop for c2 from #x40 to #xfc 14 | unless (= c2 #x7f) 15 | do (funcall fun c1 c2))) 16 | (loop for c1 from #xe0 to #xfc 17 | do (loop for c2 from #x40 to #xfc 18 | unless (= c2 #x7f) 19 | do (funcall fun c1 c2)))) 20 | 21 | (defun generate-table (file code) 22 | (with-open-file (out file 23 | :direction :output 24 | :if-exists :supersede) 25 | (map-bytes 26 | (lambda (&rest x) 27 | (ignore-errors 28 | (let ((string (iconv:iconv-to-string code (coerce x 'simple-vector)))) 29 | (format out "0x~{~2,'0x~} U+~4,'0x ~A~A~%" 30 | x 31 | (char-code (aref string 0)) 32 | (cond ((equal string (format nil "~%")) "\\n") 33 | ((equal string " ") "SPC") 34 | (t string)) 35 | (if (ignore-errors 36 | (equal x (coerce (iconv:iconv-from-string code string) 'list))) 37 | "" 38 | (format nil " 0x~{~2,'0x~}" (coerce (iconv:iconv-from-string code string) 'list)))))))))) 39 | -------------------------------------------------------------------------------- /extensions/encodings/iso-8859-1.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-encodings/iso-8859-1 2 | (:use :cl :lem/buffer)) 3 | (in-package :lem-encodings/iso-8859-1) 4 | 5 | (defclass iso-8859-1 (encoding) ()) 6 | 7 | (register-encoding 'iso-8859-1) 8 | 9 | (defmethod encoding-read ((encoding iso-8859-1) input output-char) 10 | (let (cr) 11 | (labels ((commit (c) 12 | (setf cr (funcall output-char c cr encoding)))) 13 | (loop 14 | :with buffer-size := 8192 15 | :with buffer := (make-array (list buffer-size) :element-type '(unsigned-byte 8)) 16 | :for end := (read-sequence buffer input) 17 | :until (zerop end) 18 | :do (loop :for i :from 0 :below end 19 | :do (commit (aref buffer i))) 20 | (when (< end buffer-size) 21 | (return)) 22 | :finally (commit nil))))) 23 | 24 | (defmethod encoding-write ((encoding iso-8859-1) out) 25 | (lambda (c) 26 | (when c 27 | (write-byte (char-code c) out)))) 28 | 29 | (defmethod encoding-check ((encoding iso-8859-1)) 30 | (lambda (string eof-p) 31 | (unless eof-p 32 | (loop :for c :across string 33 | :unless (char<= #.(code-char 0) 34 | c 35 | #.(code-char #xff)) 36 | :do (error "~A is not acceptable for ~S" c encoding))))) 37 | -------------------------------------------------------------------------------- /extensions/encodings/lem-encodings.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-encodings" 2 | :depends-on ("lem") 3 | :class :package-inferred-system 4 | :components ((:file "table") 5 | (:file "8bit") 6 | (:file "gb2312") 7 | (:file "euc-jp") 8 | (:file "cp932") 9 | (:file "iso-8859-1") 10 | (:file "utf-8") 11 | (:file "utf-16"))) 12 | -------------------------------------------------------------------------------- /extensions/encodings/project.lisp: -------------------------------------------------------------------------------- 1 | ;;don't edit 2 | (let ((data '(("asd" "lem-encodings")))) 3 | (dolist (n (assoc "asd" data :test 'equal)) 4 | (funcall (read-from-string "asdf:load-asd") 5 | (make-pathname :defaults *load-pathname* :name n :type "asd")))) 6 | -------------------------------------------------------------------------------- /extensions/encodings/table.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-encodings/table 2 | (:use :cl) 3 | (:export :read-table)) 4 | (in-package :lem-encodings/table) 5 | 6 | (defun decode-code (code) 7 | (assert (equal (subseq code 0 2) "0x")) 8 | (parse-integer (subseq code 2) :radix 16)) 9 | 10 | (defun decode-unicode (unicode) 11 | (assert (equal (subseq unicode 0 2) "U+")) 12 | (parse-integer (subseq unicode 2) :radix 16)) 13 | 14 | (defun decode-line (line) 15 | "line are space separated. each line are consisted of 16 | code unicode character unicode->code(optional if the iconv result is different from code)" 17 | (destructuring-bind (code unicode character &optional unicode->code) 18 | (uiop:split-string line :separator '(#\ )) 19 | (declare (ignore character)) 20 | (list (decode-code code) 21 | (decode-unicode unicode) 22 | (when unicode->code 23 | (decode-code unicode->code))))) 24 | 25 | (defun read-table (file) 26 | "read utf-8 encoded file" 27 | (loop for line in (uiop:read-file-lines file) 28 | collect (decode-line line))) 29 | -------------------------------------------------------------------------------- /extensions/erlang-mode/README.md: -------------------------------------------------------------------------------- 1 | # Erlang mode for Lem 2 | 3 | ## Features: 4 | 5 | ### Syntax Highlighting 6 | 7 | ### Shell (Run Erlang) 8 | 9 | `M-X run-erlang` 10 | 11 | ### Language Server 12 | 13 | Erlang mode will connect to your local ELP [Erlang Language Platform](https://github.com/WhatsApp/erlang-language-platform) installation. 14 | Configure the ELP binary's location by setting *lsp-elang-elp-server-path*: 15 | 16 | ``` 17 | (defvar *lsp-erlang-elp-server-path* 18 | (uiop:native-namestring "/usr/local/bin/elp") 19 | "Adapt to your system's ELP path.") 20 | ``` 21 | 22 | Currently, Erlang mode does not add any LSP features on its own. The integration is experimental with the purpose of figuring out how to use the existing Lem/LSP features and how to add Erlang specific features. -------------------------------------------------------------------------------- /extensions/erlang-mode/lem-erlang-mode.asd: -------------------------------------------------------------------------------- 1 | 2 | (defsystem "lem-erlang-mode" 3 | :depends-on ("lem" 4 | #+#.(cl:if (asdf:find-system :async-process cl:nil) '(and) '(or)) "lem-process" 5 | "lem-lisp-mode") 6 | :serial t 7 | :components ((:file "erlang-mode") 8 | (:file "lsp-config") 9 | #+#.(cl:if (asdf:find-system :async-process cl:nil) '(and) '(or)) 10 | (:file "run-erlang"))) 11 | -------------------------------------------------------------------------------- /extensions/erlang-mode/lsp-config.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-erlang-mode/lsp-config 2 | (:use :cl :lem-lsp-mode :lem-lsp-base/type)) 3 | 4 | (in-package :lem-erlang-mode/lsp-config) 5 | 6 | (defvar *lsp-erlang-elp-server-path* 7 | (uiop:native-namestring "/usr/local/bin/elp") 8 | "Adapt to your system's ELP path.") 9 | 10 | (defvar *lsp-erlang-elp-log-path* 11 | (uiop:native-namestring "~/tmp/elp.log")) 12 | 13 | (defvar *lsp-erlang-server-command* 14 | `(,*lsp-erlang-elp-server-path* 15 | "server" 16 | "--log-file" ,*lsp-erlang-elp-log-path* 17 | "--no-log-buffering") 18 | ) 19 | 20 | (define-language-spec (erlang-spec lem-erlang-mode:erlang-mode) 21 | :language-id "erlang" 22 | :root-uri-patterns '("rebar3") 23 | :command *lsp-erlang-server-command* 24 | :install-command "" 25 | :readme-url "https://github.com/WhatsApp/erlang-language-platform" 26 | :connection-mode :stdio) 27 | -------------------------------------------------------------------------------- /extensions/go-mode/lem-go-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-go-mode" 2 | :depends-on ("lem" "yason" "lem-lsp-mode") 3 | :serial t 4 | :components ((:file "go-mode") 5 | (:file "lsp-config"))) 6 | -------------------------------------------------------------------------------- /extensions/go-mode/lsp-config.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-go-mode/lsp-config 2 | (:use :cl 3 | :lem-lsp-mode 4 | :lem-lsp-base/type)) 5 | (in-package :lem-go-mode/lsp-config) 6 | 7 | (define-language-spec (go-spec lem-go-mode:go-mode) 8 | :language-id "go" 9 | :root-uri-patterns '("go.mod") 10 | :command (lambda (port) `("gopls" "serve" "-port" ,(princ-to-string port))) 11 | :install-command "go install golang.org/x/tools/gopls@latest" 12 | :readme-url "https://github.com/golang/tools/tree/master/gopls" 13 | :connection-mode :tcp) 14 | 15 | (defmethod spec-initialization-options ((spec go-spec)) 16 | (make-lsp-map "completeUnimported" +true+ 17 | "matcher" "fuzzy")) 18 | -------------------------------------------------------------------------------- /extensions/haskell-mode/lem-haskell-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-haskell-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "haskell-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/html-mode/html-mode.lisp: -------------------------------------------------------------------------------- 1 | (defpackage #:lem-html-mode 2 | (:use #:cl 3 | #:lem 4 | #:lem/language-mode) 5 | (:import-from #:lem-xml-mode 6 | #:xml-mode 7 | #:*xml-open-tag-p* 8 | #:*xml-close-tag-p* 9 | #:xml-calc-indent) 10 | (:import-from #:cl-ppcre) 11 | (:export :html-mode)) 12 | (in-package #:lem-html-mode) 13 | 14 | (define-major-mode html-mode xml-mode 15 | (:name "HTML" 16 | :keymap *html-mode-keymap* 17 | :syntax-table lem-xml-mode::*xml-syntax-table* 18 | :mode-hook *html-mode-hook*) 19 | (setf (variable-value 'enable-syntax-highlight) t 20 | (variable-value 'tab-width) 2 21 | (variable-value 'calc-indent-function) 'html-calc-indent)) 22 | 23 | (defvar *void-elements* 24 | '("area" "base" "br" "col" "embed" "hr" "img" "input" "link" "meta" "param" "source" "track" "wbr")) 25 | 26 | (defun open-tag-p (string) 27 | (ppcre:register-groups-bind (tag-content tag-name) 28 | ("^<(([^/>\\s]+)[^>]*)>$" string) 29 | (and (not (eql (aref tag-content 0) #\!)) 30 | (not (ppcre:scan "/\\s*$" tag-content)) 31 | (not (find tag-name *void-elements* :test 'string-equal))))) 32 | 33 | (defun close-tag-p (string) 34 | (and (ppcre:scan "^]+)>$" string) 35 | t)) 36 | 37 | (defun html-calc-indent (point) 38 | (let ((*xml-open-tag-p* #'open-tag-p) 39 | (*xml-close-tag-p* #'close-tag-p)) 40 | (xml-calc-indent point))) 41 | 42 | (define-file-type ("html") html-mode) 43 | -------------------------------------------------------------------------------- /extensions/html-mode/lem-html-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-html-mode" 2 | :depends-on ("lem" 3 | "lem-xml-mode" 4 | "cl-ppcre") 5 | :serial t 6 | :components ((:file "html-mode"))) 7 | -------------------------------------------------------------------------------- /extensions/java-mode/lem-java-mode.asd: -------------------------------------------------------------------------------- 1 | 2 | (defsystem "lem-java-mode" 3 | :depends-on ("lem" 4 | "lem-c-mode") 5 | :serial t 6 | :components ((:file "java-mode"))) 7 | 8 | -------------------------------------------------------------------------------- /extensions/js-mode/lem-js-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-js-mode" 2 | :depends-on ("lem" 3 | "lem-lsp-mode" 4 | "lem-xml-mode") 5 | :serial t 6 | :components ((:file "js-mode") 7 | (:file "eslint") 8 | (:file "lsp-config"))) 9 | 10 | -------------------------------------------------------------------------------- /extensions/js-mode/lsp-config.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package #:lem-js-mode/lsp-config 2 | (:use #:cl) 3 | (:export)) 4 | (in-package :lem-js-mode/lsp-config) 5 | 6 | (lem-lsp-mode:define-language-spec (js-spec lem-js-mode:js-mode) 7 | :language-id "javascript" 8 | :root-uri-patterns '("package.json" "tsconfig.json") 9 | :command '("typescript-language-server" "--stdio") 10 | :install-command "npm install -g typescript-language-server typescript" 11 | :readme-url "https://github.com/typescript-language-server/typescript-language-server" 12 | :connection-mode :stdio) 13 | -------------------------------------------------------------------------------- /extensions/json-mode/lem-json-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-json-mode" 2 | :depends-on ("lem" "lem-js-mode") 3 | :serial t 4 | :components ((:file "json-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/language-client/client.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-language-client/client 2 | (:use :cl) 3 | (:export :jsonrpc-connect 4 | :client 5 | :client-connection) 6 | #+sbcl 7 | (:lock t)) 8 | (in-package :lem-language-client/client) 9 | 10 | (defgeneric jsonrpc-connect (client)) 11 | 12 | (defclass client () 13 | ((connection 14 | :initform (jsonrpc:make-client) 15 | :reader client-connection))) 16 | -------------------------------------------------------------------------------- /extensions/language-client/lem-language-client.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-language-client" 2 | :depends-on ("jsonrpc" 3 | "lem-lsp-base" 4 | "cl-package-locks") 5 | :serial t 6 | :components ((:file "client") 7 | (:file "request"))) 8 | -------------------------------------------------------------------------------- /extensions/language-server/commands.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-language-server) 2 | 3 | (defvar *command-table* (make-hash-table :test 'equal)) 4 | 5 | (defun command-names () 6 | (alexandria:hash-table-keys *command-table*)) 7 | 8 | (defun get-command (name) 9 | (gethash name *command-table*)) 10 | 11 | (defgeneric call-command (command arguments)) 12 | 13 | (defclass command () ()) 14 | 15 | (defun execute-command (name arguments) 16 | (let ((command (get-command name))) 17 | (assert command) ; TODO: error responseを返す 18 | (call-command command arguments))) 19 | 20 | (defmacro define-lsp-command (class-name command-name (arguments) &body body) 21 | (let ((command (gensym))) 22 | `(progn 23 | (defclass ,class-name (command) ()) 24 | (defmethod call-command ((,command ,class-name) ,arguments) ,@body) 25 | (setf (gethash ,command-name *command-table*) 26 | (make-instance ',class-name))))) 27 | -------------------------------------------------------------------------------- /extensions/language-server/config.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-language-server) 2 | 3 | (defparameter *config* 4 | '(:name "cl-lsp" 5 | :version "0.1.0" 6 | :backend-port nil 7 | :backend-hostname "localhost")) 8 | 9 | (defun config (name) 10 | (getf *config* name)) 11 | 12 | (defun (setf config) (value name) 13 | (setf (getf *config* name) value)) 14 | 15 | (defun language-server-name () 16 | (config :name)) 17 | 18 | (defun language-server-version () 19 | (config :version)) 20 | -------------------------------------------------------------------------------- /extensions/language-server/controller/commands.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-language-server) 2 | 3 | (define-lsp-command eval-previous-form-command "cl-lsp.eval-last-expression" (arguments) 4 | (let ((text-document-position-params 5 | (convert-from-json (elt arguments 0) 6 | 'lsp:text-document-position-params))) 7 | (eval-last-expression text-document-position-params)) 8 | :null) 9 | 10 | (define-lsp-command eval-range-command "cl-lsp.eval-range" (arguments) 11 | (let* ((text-document-identifier (convert-from-json (elt arguments 0) 'lsp:text-document-identifier)) 12 | (range (convert-from-json (elt arguments 1) 'lsp:range)) 13 | (text-document (find-text-document text-document-identifier)) 14 | (buffer (text-document-buffer text-document))) 15 | (lem:with-point ((start (lem:buffer-point buffer)) 16 | (end (lem:buffer-point buffer))) 17 | (move-to-lsp-position start (lsp:range-start range)) 18 | (move-to-lsp-position end (lsp:range-end range)) 19 | ;; TODO 20 | ;; (eval-range start end) 21 | )) 22 | :null) 23 | 24 | (define-lsp-command interrupt-eval-command "cl-lsp.interrupt" (arguments) 25 | (let ((id (elt arguments 0))) 26 | (interrupt-eval id)) 27 | :null) 28 | -------------------------------------------------------------------------------- /extensions/language-server/controller/window.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-language-server) 2 | 3 | (defun notify-to-client (notification params) 4 | (assert (typep params (notification-message-params notification))) 5 | (let ((jsonrpc/connection:*connection* (server-jsonrpc-connection *server*))) 6 | (let ((method (notification-message-method notification)) 7 | (params (convert-to-json params))) 8 | (jsonrpc:notify (server-jsonrpc-server *server*) method params)))) 9 | 10 | (defun notify-show-message (type message) 11 | (notify-to-client (make-instance 'lsp:window/show-message) 12 | (make-instance 'lsp:show-message-params 13 | :type type 14 | :message message))) 15 | 16 | (defun notify-log-message (type message) 17 | (notify-to-client (make-instance 'lsp:window/log-message) 18 | (make-instance 'lsp:log-message-params 19 | :type type 20 | :message message))) 21 | -------------------------------------------------------------------------------- /extensions/language-server/controller/workspace.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-language-server) 2 | 3 | (define-request (execute-command-request "workspace/executeCommand") 4 | (params lsp:execute-command-params) 5 | (let ((command (lsp:execute-command-params-command params)) 6 | (arguments (lsp:execute-command-params-arguments params))) 7 | (execute-command command arguments))) 8 | -------------------------------------------------------------------------------- /extensions/language-server/editor-utils.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-language-server) 2 | 3 | (defun backward-up-list (point) 4 | (lem:backward-up-list point t)) 5 | 6 | (defun forward-up-list (point) 7 | (lem:forward-up-list point t)) 8 | 9 | (defun forward-down-list (point) 10 | (lem:forward-down-list point t)) 11 | -------------------------------------------------------------------------------- /extensions/language-server/lem-language-server.asd: -------------------------------------------------------------------------------- 1 | #+sbcl 2 | (require :sb-concurrency) 3 | 4 | (defsystem "lem-language-server" 5 | :depends-on ("alexandria" 6 | "jsonrpc" 7 | "usocket" 8 | "log4cl" 9 | "quri" 10 | "cl-change-case" 11 | "async-process" 12 | "micros" 13 | "lem" 14 | "lem-lisp-syntax" 15 | "lem-lsp-base") 16 | :serial t 17 | :components ((:file "micros-client") 18 | (:file "package") 19 | (:file "config") 20 | (:file "editor-utils") 21 | (:file "method") 22 | (:file "server") 23 | (:file "text-document") 24 | (:file "eval") 25 | (:file "commands") 26 | (:module "controller" 27 | :components ((:file "lifecycle") 28 | (:file "document-synchronization") 29 | (:file "language-features") 30 | (:file "workspace") 31 | (:file "window") 32 | (:file "commands"))))) 33 | 34 | (defsystem "lem-language-server/cli" 35 | :depends-on ("lem-language-server" 36 | "command-line-arguments") 37 | :serial t 38 | :components ((:file "cli"))) 39 | -------------------------------------------------------------------------------- /extensions/language-server/package.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-language-server 2 | (:use :cl 3 | :alexandria 4 | :lem-lsp-base/type 5 | :lem-lsp-base/converter 6 | :lem-lsp-base/utils 7 | :lem-lsp-base/yason-utils) 8 | (:export :uninitialized-error 9 | :call-lsp-method 10 | :current-server 11 | :start-server 12 | :start-mock-server 13 | :start-tcp-server 14 | :start-stdio-server 15 | :mock-server-exit-status 16 | :server-shutdown-request-received-p 17 | :with-mock-server 18 | ;; text-document.lisp 19 | :text-document-uri 20 | :text-document-language-id 21 | :text-document-version 22 | :text-document-buffer 23 | :find-text-document 24 | ;; methods 25 | :initialize-request 26 | :shutdown-request 27 | :exit-request 28 | :text-document-did-open-request 29 | :text-document-did-change-request 30 | :text-document-did-close-request) 31 | (:lock t)) 32 | -------------------------------------------------------------------------------- /extensions/legit/lem-legit.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-legit" 2 | :serial t 3 | :depends-on ("lem" "lem-patch-mode" "lem-yaml-mode" "lem-markdown-mode") 4 | :components ((:module "./" 5 | :components ((:file "porcelain") 6 | (:file "porcelain-git") 7 | (:file "porcelain-hg") 8 | (:file "porcelain-fossil") 9 | (:file "legit-common") 10 | (:file "peek-legit") 11 | (:file "legit") 12 | (:file "legit-rebase") 13 | (:file "legit-commit"))) 14 | (:module "scripts" 15 | :components ((:static-file "dumbrebaseeditor.sh"))))) 16 | -------------------------------------------------------------------------------- /extensions/legit/lem-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/extensions/legit/lem-status.png -------------------------------------------------------------------------------- /extensions/legit/scripts/dumbrebaseeditor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Helper for a Git interactive rebase. 3 | # 4 | # git --interactive creates the rebase file we need in .git/rebase-merge/git-rebase-todo 5 | # but the git-rebase process opens $EDITOR and waits for it to exit gracefully. 6 | # 7 | # This dumb editor is not an editor, so we can edit the rebase file with Lem, 8 | # but this script catches a SIGTERM signal and exits successfulyl, so git-rebase 9 | # is happy and terminates the rebase and all is well (on Unix). 10 | 11 | function ok { 12 | exit 0 13 | } 14 | 15 | trap ok SIGTERM 16 | echo "dumbrebaseeditor_pid:$$" 17 | 18 | while : 19 | do 20 | sleep 0.1 21 | done 22 | -------------------------------------------------------------------------------- /extensions/legit/test.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/extensions/legit/test.txt -------------------------------------------------------------------------------- /extensions/lem-base16-themes/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 Łukasz Pankowski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /extensions/lem-base16-themes/README.md: -------------------------------------------------------------------------------- 1 | # base16 themes for Lem editor/IDE 2 | 3 | ## Installation 4 | 5 | To use base16 themes in Lem editor run 6 | 7 | ``` 8 | $ ros install lukpank/lem-base16-themes 9 | ``` 10 | 11 | then add to your `~/.lem/init.lisp` the following lines 12 | 13 | ``` 14 | (load-library "base16-themes") 15 | (load-theme "espresso") 16 | ``` 17 | 18 | changing the theme `espresso` to the theme you want to use. 19 | 20 | You can also change the theme interactively with `M-x load-theme`. 21 | 22 | ## Regenerating themes 23 | 24 | To regenerate `src/themes.lisp` run in slime REPL 25 | 26 | ``` 27 | (load "/path/to/lem-base16-themes/lem-base16-themes-generate.asd") 28 | (ql:quickload "lem-base16-themes-generate") 29 | (lem-base16-themes-generate:regenerate-themes) 30 | ``` 31 | 32 | ## License 33 | 34 | Licensed under [MIT License](https://github.com/lukpank/lem-base16-themes/blob/master/LICENSE). 35 | 36 | ## Author 37 | 38 | Łukasz Pankowski 39 | -------------------------------------------------------------------------------- /extensions/lem-base16-themes/lem-base16-themes-generate.asd: -------------------------------------------------------------------------------- 1 | (asdf:defsystem "lem-base16-themes-generate" 2 | :author "Łukasz Pankowski" 3 | :license "MIT" 4 | :depends-on ("cl-base16" "cl-mustache") 5 | :components ((:module "src" 6 | :components 7 | ((:file "generate"))))) 8 | -------------------------------------------------------------------------------- /extensions/lem-base16-themes/lem-base16-themes.asd: -------------------------------------------------------------------------------- 1 | (asdf:defsystem "lem-base16-themes" 2 | :author "Łukasz Pankowski" 3 | :license "MIT" 4 | :depends-on (#:lem) 5 | :components ((:module "src" 6 | :components 7 | ((:file "package") 8 | (:file "macros") 9 | (:file "themes" :depends-on ("macros")))))) 10 | -------------------------------------------------------------------------------- /extensions/lem-base16-themes/src/generate.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | (defpackage :lem-base16-themes-generate 3 | (:use :common-lisp) 4 | (:export 5 | #:generate 6 | #:regenerate-themes)) 7 | 8 | (in-package :lem-base16-themes-generate) 9 | 10 | (defparameter *base-dir* (directory-namestring (asdf:system-relative-pathname :lem-base16-themes-generate "lem-base16-themes.asd"))) 11 | 12 | (defun generate (out) 13 | (format out ";;; AUTOGENERATED~%~%(in-package :lem-base16-themes)~%") 14 | (let ((template (merge-pathnames "templates/default.mustache" *base-dir*))) 15 | (loop :for scheme-dir :in (uiop:subdirectories (merge-pathnames "schemes/" cl-base16:*source-dir*)) 16 | :do (unless (uiop:string-prefix-p "." (first (last (pathname-directory scheme-dir)))) 17 | (loop :for scheme :in (uiop:directory-files scheme-dir) 18 | :do (if (string= "yaml" (pathname-type scheme)) 19 | (format out "~%~A" (mustache:render* template (cl-base16::load-scheme scheme))))))))) 20 | 21 | (defun regenerate-themes () 22 | (with-open-file (out (merge-pathnames "src/themes.lisp" *base-dir*) 23 | :direction :output :external-format :utf-8 :if-exists :supersede) 24 | (generate out))) 25 | -------------------------------------------------------------------------------- /extensions/lem-base16-themes/src/package.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | (defpackage :lem-base16-themes 3 | (:use :common-lisp)) 4 | -------------------------------------------------------------------------------- /extensions/lem-base16-themes/templates/default.mustache: -------------------------------------------------------------------------------- 1 | ;; Scheme: {{scheme-slug}} 2 | ;; Scheme author: {{scheme-author}} 3 | 4 | (define-base16-color-theme "{{scheme-slug}}" 5 | :base00 "#{{base00-hex}}" 6 | :base01 "#{{base01-hex}}" 7 | :base02 "#{{base02-hex}}" 8 | :base03 "#{{base03-hex}}" 9 | :base04 "#{{base04-hex}}" 10 | :base05 "#{{base05-hex}}" 11 | :base06 "#{{base06-hex}}" 12 | :base07 "#{{base07-hex}}" 13 | :base08 "#{{base08-hex}}" 14 | :base09 "#{{base09-hex}}" 15 | :base0A "#{{base0A-hex}}" 16 | :base0B "#{{base0B-hex}}" 17 | :base0C "#{{base0C-hex}}" 18 | :base0D "#{{base0D-hex}}" 19 | :base0E "#{{base0E-hex}}" 20 | :base0F "#{{base0F-hex}}") 21 | -------------------------------------------------------------------------------- /extensions/lem-dashboard/lem-dashboard.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-dashboard" 2 | :depends-on (:lem) 3 | :serial t 4 | :components ((:file "lem-dashboard") 5 | (:file "dashboard-items") 6 | (:file "default-dashboard"))) 7 | -------------------------------------------------------------------------------- /extensions/lisp-mode/connections.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-mode/connections 2 | (:use :cl) 3 | (:export :connection-list 4 | :add-connection 5 | :remove-connection)) 6 | (in-package :lem-lisp-mode/connections) 7 | 8 | (defvar *connection-list* '()) 9 | 10 | (defun connection-list () 11 | (copy-list *connection-list*)) 12 | 13 | (defun add-connection (connection) 14 | (push connection *connection-list*)) 15 | 16 | (defun remove-connection (connection) 17 | (setf *connection-list* (delete connection *connection-list*)) 18 | (values)) 19 | -------------------------------------------------------------------------------- /extensions/lisp-mode/errors.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-mode/errors 2 | (:use :cl) 3 | (:export :disconnected 4 | :change-connection)) 5 | (in-package :lem-lisp-mode/errors) 6 | 7 | (define-condition disconnected (simple-condition) 8 | ()) 9 | 10 | (define-condition change-connection (simple-condition) 11 | ()) 12 | -------------------------------------------------------------------------------- /extensions/lisp-mode/ext/class-browser.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-mode/class-browser 2 | (:use :cl :lem :lem-lisp-mode/internal) 3 | (:export :display-class-inheritance-tree 4 | :lisp-browse-class-as-tree)) 5 | (in-package :lem-lisp-mode/class-browser) 6 | 7 | (defmethod display-class-inheritance-tree (buffer-name class-name) 8 | (editor-error "Unimplemented")) 9 | 10 | (define-command lisp-browse-class-as-tree () () 11 | (check-connection) 12 | (let ((class-name (or (symbol-string-at-point (current-point)) 13 | (prompt-for-symbol-name "Class name: ")))) 14 | (display-class-inheritance-tree "*Class Browser*" class-name))) 15 | -------------------------------------------------------------------------------- /extensions/lisp-mode/ext/defstruct-to-defclass.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-mode/defstruct-to-defclass 2 | (:use :cl :lem)) 3 | (in-package :lem-lisp-mode/defstruct-to-defclass) 4 | 5 | (define-command lisp-defstruct-to-defclass () () 6 | (lem-lisp-syntax:defstruct-to-defclass (current-point))) 7 | -------------------------------------------------------------------------------- /extensions/lisp-mode/ext/quickdocs.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-mode/quickdocs 2 | (:use :cl 3 | :lem 4 | :lem-lisp-mode/internal)) 5 | (in-package :lem-lisp-mode/quickdocs) 6 | 7 | (defvar *quickdocs-url* "https://quickdocs.org/") 8 | 9 | (defvar *quickdocs-check-url* nil 10 | "Boolean variable, if true, the function `lisp-quickdocs-at-point' ensure 11 | that the reference exists in the webpage, adding consistency but more delay. 12 | By default, is set to nil so the execution is faster.") 13 | 14 | (define-command lisp-quickdocs-at-point (point) ((current-point)) 15 | (let* ((symbol (cl-ppcre:regex-replace-all 16 | ":|#" 17 | (symbol-string-at-point point) "")) 18 | (url (format nil "~a~a" *quickdocs-url* symbol)) 19 | (status-response 20 | (and *quickdocs-check-url* 21 | (second (multiple-value-list (ignore-errors 22 | (dexador:get url))))))) 23 | (if (or (and (numberp status-response) 24 | (= status-response 200)) 25 | (not *quickdocs-check-url*)) 26 | (open-external-file url) 27 | (message "The symbol ~a, doesn't correspond to a ASDF system on Quickdocs." 28 | symbol)))) 29 | -------------------------------------------------------------------------------- /extensions/lisp-mode/ext/self-insert-hook.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-mode/self-insert-hook 2 | (:use :cl :lem)) 3 | (in-package :lem-lisp-mode/self-insert-hook) 4 | 5 | (defmethod execute :before ((mode lem-lisp-mode/internal:lisp-mode) (command self-insert) argument) 6 | (when (eql #\) (get-self-insert-char)) 7 | (unless (or (syntax-escape-char-p (character-at (current-point) -1)) 8 | (in-string-or-comment-p (current-point))) 9 | (with-point ((point (current-point))) 10 | (unless (scan-lists point -1 1 t) 11 | (editor-error "No matching ')' (can be inserted with \"C-q )\")")))))) 12 | 13 | (defmethod execute :after ((mode lem-lisp-mode/internal:lisp-mode) (command self-insert) argument) 14 | (when (eql #\space (get-self-insert-char)) 15 | (lem-lisp-mode/autodoc:lisp-autodoc))) 16 | -------------------------------------------------------------------------------- /extensions/lisp-mode/file-conversion.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-lisp-mode/internal) 2 | 3 | (defvar *file-conversion-map* '() 4 | "This variable is an alist for converting remote file names to local file names. 5 | Uses include mapping files in docker to files in the local environment. 6 | 7 | For example, set the following. 8 | \(setf *file-conversion-map* 9 | `((\"/app/\" . 10 | ,(merge-pathnames \"common-lisp/my-project/\" (user-homedir-pathname))))) 11 | ") 12 | 13 | (defun convert-remote-to-local-file (filename) 14 | (loop :for (remote-file . local-file) :in *file-conversion-map* 15 | :do (when (alexandria:starts-with-subseq remote-file filename) 16 | (return (concatenate 'string local-file (subseq filename (length remote-file))))) 17 | :finally (return filename))) 18 | 19 | (defun convert-local-to-remote-file (filename) 20 | (loop :for (remote-file . local-file) :in *file-conversion-map* 21 | :do (when (alexandria:starts-with-subseq local-file filename) 22 | (return (concatenate 'string remote-file (subseq filename (length local-file))))) 23 | :finally (return filename))) 24 | -------------------------------------------------------------------------------- /extensions/lisp-mode/message-dispatcher.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-mode/message-dispatcher 2 | (:use :cl) 3 | (:export :get-message-dispatcher 4 | :define-message 5 | :dispatch-message)) 6 | (in-package :lem-lisp-mode/message-dispatcher) 7 | 8 | (defvar *message-dispatcher* (make-hash-table :test 'eq)) 9 | 10 | (defun get-message-dispatcher (name) 11 | (gethash name *message-dispatcher*)) 12 | 13 | (defmacro define-message ((name &rest params) &body body) 14 | (alexandria:with-unique-names (message) 15 | (let ((fn-name (alexandria:symbolicate "$$MESSAGE-DISPATCHER-" name))) 16 | `(progn 17 | (defun ,fn-name (,message) 18 | (destructuring-bind (,@params) (rest ,message) 19 | ,@body)) 20 | (setf (gethash ,name *message-dispatcher*) 21 | ',fn-name))))) 22 | 23 | (defvar *event-log* '()) 24 | 25 | (defun log-message (string) 26 | "Log a message." 27 | (push string *event-log*)) 28 | 29 | (defvar *event-hooks* '()) 30 | 31 | (defun dispatch-message (message) 32 | (log-message (prin1-to-string message)) 33 | (dolist (e *event-hooks*) 34 | (when (funcall e message) 35 | (return-from dispatch-message))) 36 | (alexandria:when-let (dispatcher (get-message-dispatcher (first message))) 37 | (funcall dispatcher message))) 38 | -------------------------------------------------------------------------------- /extensions/lisp-mode/message.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-lisp-mode/internal) 2 | 3 | (defun display-message (control-string &rest format-arguments) 4 | (show-message (apply #'format nil control-string format-arguments) 5 | :timeout nil)) 6 | -------------------------------------------------------------------------------- /extensions/lisp-mode/package.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-lisp-mode 2 | (:use :cl) 3 | (:use-reexport :lem-lisp-mode/internal) 4 | (:use-reexport :lem-lisp-mode/implementation) 5 | (:use-reexport :lem-lisp-mode/sldb) 6 | (:use-reexport :lem-lisp-mode/inspector) 7 | (:use-reexport :lem-lisp-mode/eval) 8 | (:use-reexport :lem-lisp-mode/paren-coloring)) 9 | -------------------------------------------------------------------------------- /extensions/lisp-mode/read-only-sources.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-lisp-mode/read-only-sources 2 | (:use :cl) 3 | (:import-from :lem/read-only-sources 4 | :define-read-only-source)) 5 | (in-package :lem-lisp-mode/read-only-sources) 6 | 7 | (define-read-only-source sbcl-source (directory) 8 | (alexandria:when-let (connection (lem-lisp-mode/internal:current-connection)) 9 | (dolist (pattern (lem-lisp-mode/connection:connection-system-file-patterns connection)) 10 | (when (pathname-match-p directory pattern) 11 | (return t))))) 12 | 13 | (define-read-only-source quicklisp-dists (directory) 14 | (search "/dists/quicklisp/software/" directory)) 15 | -------------------------------------------------------------------------------- /extensions/lisp-mode/reader.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-lisp-mode/reader 2 | (:use :cl) 3 | (:export :read-from-string*)) 4 | (in-package :lem-lisp-mode/reader) 5 | 6 | (defun read-atom (in) 7 | (let ((token 8 | (coerce (loop :for c := (peek-char nil in nil) 9 | :until (or (null c) (member c '(#\( #\) #\space #\newline #\tab))) 10 | :collect c 11 | :do (read-char in)) 12 | 'string))) 13 | (handler-case (values (read-from-string token) nil) 14 | (error () 15 | (ppcre:register-groups-bind (prefix name) ("(.*?)::?(.*)" token) 16 | (values (intern (string-upcase (string-left-trim ":" name)) 17 | :keyword) 18 | (when prefix 19 | (read-from-string prefix)))))))) 20 | 21 | (defun read-list (in) 22 | (read-char in) 23 | (loop :until (eql (peek-char t in) #\)) 24 | :collect (read-ahead in) 25 | :finally (read-char in))) 26 | 27 | (defun read-sharp (in) 28 | (read-char in) 29 | (case (peek-char nil in) 30 | ((#\() 31 | (let ((list (read-list in))) 32 | (make-array (length list) :initial-contents list))) 33 | ((#\\) 34 | (read-char in) 35 | (read-char in)) 36 | (otherwise 37 | (unread-char #\# in)))) 38 | 39 | (defun read-ahead (in) 40 | (let ((c (peek-char t in))) 41 | (case c 42 | ((#\() 43 | (read-list in)) 44 | ((#\") 45 | (read in)) 46 | ((#\#) 47 | (read-sharp in)) 48 | (otherwise 49 | (read-atom in))))) 50 | 51 | (defun read-from-string* (string) 52 | (with-input-from-string (in string) 53 | (read-ahead in))) 54 | -------------------------------------------------------------------------------- /extensions/lisp-mode/test-api.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-mode/test-api 2 | (:use :cl) 3 | (:export :*disable-self-connect*)) 4 | (in-package :lem-lisp-mode/test-api) 5 | 6 | (defvar *disable-self-connect* nil) 7 | -------------------------------------------------------------------------------- /extensions/lisp-mode/ui-mode.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-mode/ui-mode 2 | (:use :cl 3 | :lem) 4 | (:import-from :lem/button 5 | :button-at 6 | :button-action 7 | :forward-button) 8 | (:export :lisp-ui-mode 9 | :lisp-ui-default-action 10 | :lisp-ui-forward-button)) 11 | (in-package :lem-lisp-mode/ui-mode) 12 | 13 | (define-major-mode lisp-ui-mode nil 14 | (:name "lisp-ui" ;TODO 15 | :keymap *lisp-ui-keymap*) 16 | (setf (buffer-read-only-p (current-buffer)) t)) 17 | 18 | (define-key *lisp-ui-keymap* "Return" 'lisp-ui-default-action) 19 | (define-key *lisp-ui-keymap* "Tab" 'lisp-ui-forward-button) 20 | (define-key *lisp-ui-keymap* "q" 'quit-active-window) 21 | (define-key *lisp-ui-keymap* "M-q" 'quit-active-window) 22 | 23 | (define-command lisp-ui-default-action () () 24 | (let ((button (button-at (current-point)))) 25 | (when button (button-action button)))) 26 | 27 | (define-command lisp-ui-forward-button () () 28 | (let ((p (current-point))) 29 | (or (forward-button p) 30 | (progn 31 | (buffer-start p) 32 | (forward-button p))))) 33 | -------------------------------------------------------------------------------- /extensions/lisp-syntax/lem-lisp-syntax.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-lisp-syntax" 2 | :depends-on ("lem" "cl-ppcre" "micros" "trivia") 3 | :serial t 4 | :components ((:file "indent") 5 | (:file "syntax-table") 6 | (:file "misc") 7 | (:file "enclosing") 8 | (:file "parse-for-autodoc") 9 | (:file "defstruct-to-defclass") 10 | (:file "lem-lisp-syntax"))) 11 | -------------------------------------------------------------------------------- /extensions/lisp-syntax/lem-lisp-syntax.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-lisp-syntax 2 | (:use :cl) 3 | (:use-reexport 4 | :lem-lisp-syntax.indent 5 | :lem-lisp-syntax.syntax-table 6 | :lem-lisp-syntax.misc 7 | :lem-lisp-syntax.enclosing 8 | :lem-lisp-syntax.parse-for-autodoc 9 | :lem-lisp-syntax.defstruct-to-defclass)) 10 | -------------------------------------------------------------------------------- /extensions/lisp-syntax/misc.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-syntax.misc 2 | (:use :cl :lem) 3 | (:export 4 | :beginning-of-defun 5 | :top-of-defun) 6 | #+sbcl 7 | (:lock t)) 8 | (in-package :lem-lisp-syntax.misc) 9 | 10 | (defun beginning-of-defun (point n) 11 | (with-point ((start point)) 12 | (if (minusp n) 13 | (dotimes (_ (- n) point) 14 | (if (start-line-p point) 15 | (line-offset point -1) 16 | (line-start point)) 17 | (loop 18 | (when (char= #\( (character-at point 0)) 19 | (return)) 20 | (unless (line-offset point -1) 21 | (move-point point start) 22 | (return-from beginning-of-defun nil)))) 23 | (dotimes (_ n point) 24 | (loop 25 | (unless (line-offset point 1) 26 | (move-point point start) 27 | (return-from beginning-of-defun nil)) 28 | (when (char= #\( (character-at point 0)) 29 | (return))))))) 30 | 31 | (defun top-of-defun (point) 32 | (beginning-of-defun (line-end point) -1)) 33 | -------------------------------------------------------------------------------- /extensions/lisp-syntax/syntax-table.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lisp-syntax.syntax-table 2 | (:use :cl :lem) 3 | (:export :*syntax-table*) 4 | #+sbcl 5 | (:lock t)) 6 | (in-package :lem-lisp-syntax.syntax-table) 7 | 8 | (flet ((f (c1 c2 step-fn) 9 | (when c1 10 | (when (and (member c1 '(#\#)) 11 | (or (alphanumericp c2) 12 | (member c2 '(#\+ #\-)))) 13 | (funcall step-fn))))) 14 | 15 | (defun skip-expr-prefix-forward (point) 16 | (f (character-at point 0) 17 | (character-at point 1) 18 | (lambda () 19 | (character-offset point 2)))) 20 | 21 | (defun skip-expr-prefix-backward (point) 22 | (f (character-at point -2) 23 | (character-at point -1) 24 | (lambda () 25 | (character-offset point -2))))) 26 | 27 | (defvar *syntax-table* 28 | (make-syntax-table 29 | :space-chars '(#\space #\tab #\newline #\page) 30 | :symbol-chars '(#\+ #\- #\< #\> #\/ #\* #\& #\= #\. #\? #\_ #\! #\$ #\% #\: #\@ #\[ #\] 31 | #\^ #\{ #\} #\~ #\# #\|) 32 | :paren-pairs '((#\( . #\)) 33 | (#\[ . #\]) 34 | (#\{ . #\})) 35 | :string-quote-chars '(#\") 36 | :escape-chars '(#\\) 37 | :fence-chars '(#\|) 38 | :expr-prefix-chars '(#\' #\, #\@ #\# #\`) 39 | :expr-prefix-forward-function 'skip-expr-prefix-forward 40 | :expr-prefix-backward-function 'skip-expr-prefix-backward 41 | :line-comment-string ";" 42 | :block-comment-pairs '(("#|" . "|#")))) 43 | -------------------------------------------------------------------------------- /extensions/lsp-base/lem-lsp-base.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-lsp-base" 2 | :depends-on ("lem" "cl-change-case" "bordeaux-threads" "jsonrpc" "trivia.level2" "quri") 3 | :serial t 4 | :components ((:file "yason-utils") 5 | (:file "type") 6 | (:file "protocol-generator") 7 | (:file "protocol-3-17") 8 | (:file "converter") 9 | (:file "utils"))) 10 | -------------------------------------------------------------------------------- /extensions/lsp-base/utils.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lsp-base/utils 2 | (:use :cl) 3 | (:import-from :quri) 4 | (:export :pathname-to-uri 5 | :uri-to-pathname 6 | :point-lsp-line-number 7 | :point-to-lsp-position 8 | :points-to-lsp-range 9 | :move-to-lsp-position 10 | :destructuring-lsp-range)) 11 | (in-package :lem-lsp-base/utils) 12 | 13 | (defun pathname-to-uri (pathname) 14 | (format nil "file://~A" (namestring pathname))) 15 | 16 | (defun uri-to-pathname (uri) 17 | (pathname (quri:uri-path (quri:uri uri)))) 18 | 19 | (defun point-lsp-line-number (point) 20 | (1- (lem:line-number-at-point point))) 21 | 22 | (defun point-to-lsp-position (point) 23 | (make-instance 'lsp:position 24 | :line (point-lsp-line-number point) 25 | :character (lem:point-charpos point))) 26 | 27 | (defun points-to-lsp-range (start end) 28 | (make-instance 'lsp:range 29 | :start (point-to-lsp-position start) 30 | :end (point-to-lsp-position end))) 31 | 32 | (defun move-to-lsp-position (point position) 33 | (check-type point lem:point) 34 | (check-type position lsp:position) 35 | (let ((line (lsp:position-line position)) 36 | (character (lsp:position-character position))) 37 | (lem:move-to-line point (1+ line)) 38 | (lem:character-offset (lem:line-start point) character) 39 | point)) 40 | 41 | (defun destructuring-lsp-range (start end range) 42 | (move-to-lsp-position start (lsp:range-start range)) 43 | (move-to-lsp-position end (lsp:range-end range)) 44 | (values)) 45 | -------------------------------------------------------------------------------- /extensions/lsp-base/yason-utils.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lsp-base/yason-utils 2 | (:use :cl) 3 | (:export :with-yason-bindings 4 | :parse-json)) 5 | (in-package :lem-lsp-base/yason-utils) 6 | 7 | (defparameter *yason-bindings* 8 | '((yason:*parse-json-null-as-keyword* . t) 9 | (yason:*parse-json-arrays-as-vectors* . t) 10 | (jsonrpc/yason:*parse-json-null-as-keyword* . t) 11 | (jsonrpc/yason:*parse-json-arrays-as-vectors* . t))) 12 | 13 | (defmacro with-yason-bindings (() &body body) 14 | `(call-with-yason-bindings (lambda () ,@body))) 15 | 16 | (defun call-with-yason-bindings (function) 17 | (let ((bt2:*default-special-bindings* 18 | (append *yason-bindings* 19 | bt2:*default-special-bindings*))) 20 | (progv (mapcar #'car *yason-bindings*) 21 | (mapcar #'cdr *yason-bindings*) 22 | (funcall function)))) 23 | 24 | (defun parse-json (input) 25 | (with-yason-bindings () 26 | (yason:parse input))) 27 | -------------------------------------------------------------------------------- /extensions/lsp-mode/client-capabilities.json: -------------------------------------------------------------------------------- 1 | { 2 | "workspace": {}, 3 | "textDocument": { 4 | "synchronization": { 5 | "didSave": true 6 | }, 7 | "publishDiagnostics": { 8 | "relatedInformation": true 9 | }, 10 | "completion": { 11 | "completionItem": { 12 | "snippetSupport": false 13 | }, 14 | "contextSupport": true 15 | }, 16 | "hover": {}, 17 | "signatureHelp": { 18 | "signatureInformation": { 19 | "documentationFormat": [ 20 | "plaintext", 21 | "markdown" 22 | ], 23 | "parameterInformation": { 24 | "labelOffsetSupport": true 25 | }, 26 | "activeParameterSupport": true 27 | }, 28 | "contextSupport": true 29 | }, 30 | "definition": { 31 | "linkSupport": false 32 | }, 33 | "typeDefinition": { 34 | "linkSupport": false 35 | }, 36 | "implementation": { 37 | "linkSupport": false 38 | }, 39 | "references": {}, 40 | "documentSymbol": { 41 | "hierarchicalDocumentSymbolSupport": true 42 | }, 43 | "codeAction": { 44 | "isPreferredSupport": true, 45 | "disabledSupport": true, 46 | "codeActionLiteralSupport": { 47 | "codeActionKind": { 48 | "valueSet": [ 49 | "", 50 | "quickfix", 51 | "refactor", 52 | "refactor.extract", 53 | "refactor.inline", 54 | "refactor.rewrite", 55 | "source", 56 | "source.organizeImports" 57 | ] 58 | } 59 | }, 60 | "dynamicRegistration": false 61 | }, 62 | "formatting": {}, 63 | "rangeFormatting": {}, 64 | "onTypeFormatting": {}, 65 | "rename": {} 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /extensions/lsp-mode/client.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lsp-mode/client 2 | (:use :cl) 3 | (:import-from :jsonrpc) 4 | (:import-from :lem-lsp-mode/lem-stdio-transport 5 | :lem-stdio-transport) 6 | (:export :dispose 7 | :tcp-client 8 | :stdio-client) 9 | #+sbcl 10 | (:lock t)) 11 | (in-package :lem-lsp-mode/client) 12 | 13 | (defgeneric dispose (client)) 14 | 15 | (defclass tcp-client (lem-language-client/client:client) 16 | ((port 17 | :initarg :port 18 | :reader tcp-client-port) 19 | (process 20 | :initform nil 21 | :initarg :process 22 | :reader tcp-client-process))) 23 | 24 | (defmethod lem-language-client/client:jsonrpc-connect ((client tcp-client)) 25 | (jsonrpc:client-connect (lem-language-client/client:client-connection client) 26 | :mode :tcp 27 | :port (tcp-client-port client))) 28 | 29 | (defmethod dispose ((client tcp-client)) 30 | (when (tcp-client-process client) 31 | (lem-process:delete-process (tcp-client-process client)))) 32 | 33 | (defclass stdio-client (lem-language-client/client:client) 34 | ((process :initarg :process 35 | :reader stdio-client-process))) 36 | 37 | (defmethod lem-language-client/client:jsonrpc-connect ((client stdio-client)) 38 | (jsonrpc/client:client-connect-using-class (lem-language-client/client:client-connection client) 39 | 'lem-stdio-transport 40 | :process (stdio-client-process client))) 41 | 42 | (defmethod dispose ((client stdio-client)) 43 | (async-process:delete-process (stdio-client-process client))) 44 | -------------------------------------------------------------------------------- /extensions/lsp-mode/lem-lsp-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-lsp-mode" 2 | :depends-on ("alexandria" 3 | "cl-package-locks" 4 | "jsonrpc" 5 | "jsonrpc/transport/stdio" 6 | "jsonrpc/transport/tcp" 7 | "quri" 8 | "trivia" 9 | "lem-process" 10 | "lem-language-client" 11 | "lem-language-server") 12 | :serial t 13 | :components ((:file "async-process-stream") 14 | (:file "lem-stdio-transport") 15 | (:file "client") 16 | (:file "spec") 17 | (:file "lsp-mode"))) 18 | -------------------------------------------------------------------------------- /extensions/lua-mode/lem-lua-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-lua-mode" 2 | :depends-on ("lem" "yason" "lem-lsp-mode") 3 | :serial t 4 | :components ((:file "lua-mode") 5 | (:file "lsp-config"))) 6 | -------------------------------------------------------------------------------- /extensions/lua-mode/lsp-config.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-lua-mode/lsp-config 2 | (:use :cl :lem-lsp-mode :lem-lsp-base/type)) 3 | (in-package :lem-lua-mode/lsp-config) 4 | 5 | (define-language-spec (lua-spec lem-lua-mode:lua-mode) 6 | :language-id "lua" 7 | ;; I have no idea what a correct file may identify a root of a Lua project 8 | :root-uri-patterns '(".git") 9 | :command '("lua-language-server") 10 | :readme-url "https://github.com/luals/lua-language-server" 11 | :connection-mode :stdio) 12 | -------------------------------------------------------------------------------- /extensions/makefile-mode/lem-makefile-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-makefile-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "makefile-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/markdown-mode/example.md: -------------------------------------------------------------------------------- 1 | # Hello 2 | 3 | ## Test 4 | 5 | ### Subheader 6 | 7 | #### Deeper header 8 | 9 | ##### Even deeper 10 | 11 | ###### Deepest header 12 | 13 | This is a paragraph with **bold text**, *italic text*, and __underlined text__. 14 | 15 | Here is some `inline code` and a [link](https://example.com). 16 | 17 | > This is a blockquote. 18 | > More blockquote text. 19 | > > Nested blockquote text. 20 | 21 | Lists: 22 | 23 | - foo 24 | - bar 25 | - baz 26 | 27 | * hoge 28 | * piyo 29 | 30 | + hoge 31 | + piyo 32 | 33 | 1. one 34 | 2. two 35 | 3. three 36 | 37 | Task list example: 38 | 39 | - [ ] Incomplete task 40 | - [x] Completed task 41 | - [ ] Another task to do 42 | 43 | Table: 44 | 45 | | Header 1 | Header 2 | Header 3 | 46 | |----------|----------|----------| 47 | | Row 1, Col 1 | Row 1, Col 2 | Row 1, Col 3 | 48 | | Row 2, Col 1 | Row 2, Col 2 | Row 2, Col 3 | 49 | 50 | Code: 51 | 52 | ```lisp 53 | (defpackage :foo 54 | (:use :cl)) 55 | (in-package :foo) 56 | 57 | (defun hello () 58 | (write-line "Hello World")) 59 | ``` 60 | 61 | ```c 62 | #include 63 | 64 | int main(void) { 65 | printf("Hello World\n"); 66 | } 67 | ``` 68 | 69 | ```python 70 | def greet(name): 71 | print(f"Hello, {name}!") 72 | 73 | greet("World") 74 | ``` 75 | 76 | Inline formatting combinations: 77 | - **Bold and *italic* text** 78 | - *Italic and `inline code`* 79 | - [A link with **bold** text](https://example.com) 80 | 81 | --- 82 | 83 | Metadata: 84 | 85 | Title: Expanded Comprehensive Markdown Test File 86 | Author: AI Assistant 87 | Date: 2024-08-05 -------------------------------------------------------------------------------- /extensions/markdown-mode/internal.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-markdown-mode/internal 2 | (:use :cl) 3 | (:export :on-save 4 | :on-kill 5 | :on-change 6 | :preview 7 | :on-save-default 8 | :on-kill-default 9 | :on-change-default 10 | :preview-default)) 11 | (in-package :lem-markdown-mode/internal) 12 | 13 | (defparameter *view-type* :external-browser) 14 | 15 | (defgeneric on-save (buffer view-type)) 16 | (defgeneric on-kill (buffer view-type)) 17 | (defgeneric on-change (buffer view-type)) 18 | (defgeneric preview (buffer view-type)) 19 | 20 | (defun on-save-default (buffer) 21 | (on-save buffer *view-type*)) 22 | 23 | (defun on-kill-default (buffer) 24 | (on-kill buffer *view-type*)) 25 | 26 | (defun on-change-default (buffer) 27 | (on-change buffer *view-type*)) 28 | 29 | (defun preview-default (buffer) 30 | (preview buffer *view-type*)) 31 | -------------------------------------------------------------------------------- /extensions/markdown-mode/languages.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-markdown-mode/languages 2 | (:use :cl) 3 | (:export :find-mode-by-language-name)) 4 | (in-package :lem-markdown-mode/languages) 5 | 6 | (defparameter *language-mode-pairs* 7 | `(("common-lisp" . lem-lisp-mode:lisp-mode) 8 | ("lisp" . lem-lisp-mode:lisp-mode) 9 | ("emacs-lisp" . lem-elisp-mode:elisp-mode) 10 | ("shell" . lem-posix-shell-mode:posix-shell-mode) 11 | ("json" . lem-json-mode:json-mode))) 12 | 13 | (defun find-mode-by-language-name (language-name) 14 | (or (cdr (assoc language-name *language-mode-pairs* :test #'equal)) 15 | (lem:find-mode language-name))) 16 | -------------------------------------------------------------------------------- /extensions/markdown-mode/lem-markdown-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-markdown-mode" 2 | :depends-on ("lem" 3 | "3bmd" 4 | "3bmd-ext-code-blocks" 5 | "lisp-preprocessor" 6 | "trivial-ws" 7 | "trivial-open-browser" 8 | "lem-lisp-mode" 9 | "lem-elisp-mode" 10 | "lem-posix-shell-mode" 11 | "lem-json-mode") 12 | :serial t 13 | :components ((:file "internal") 14 | (:file "languages") 15 | (:file "syntax-parser") 16 | (:file "markdown-mode") 17 | (:module "preview" 18 | :serial t 19 | :components ((:file "preview") 20 | (:file "external-browser") 21 | (:file "html-buffer"))))) 22 | -------------------------------------------------------------------------------- /extensions/markdown-mode/preview/external-browser-preview.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | #{ (princ $body) #} 12 | 13 | 14 | -------------------------------------------------------------------------------- /extensions/markdown-mode/preview/html-buffer.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-markdown-mode/preview/html-buffer 2 | (:use :cl :lem) 3 | (:import-from :lem-markdown-mode/preview/preview 4 | :render)) 5 | (in-package :lem-markdown-mode/preview/html-buffer) 6 | 7 | (defun preview-buffer-name (buffer) 8 | (format nil 9 | "*Markdown Preview ~A*" 10 | (buffer-name buffer))) 11 | 12 | (defmethod lem-markdown-mode/internal:preview (buffer (view-type (eql :html-buffer))) 13 | (let* ((html (render (buffer-text buffer))) 14 | (html (format nil " 15 | 16 | ~A 17 | " html)) 18 | (html-buffer (lem:make-html-buffer (preview-buffer-name buffer) 19 | html))) 20 | (pop-to-buffer html-buffer))) 21 | 22 | (defmethod lem-markdown-mode/internal:on-save (buffer (view-type (eql :html-buffer))) 23 | (when (get-buffer (preview-buffer-name buffer)) 24 | (lem-markdown-mode/internal:preview buffer :html-buffer))) 25 | 26 | (defmethod lem-markdown-mode/internal:on-kill (buffer (view-type (eql :html-buffer))) 27 | ) 28 | 29 | (defmethod lem-markdown-mode/internal:on-change (buffer (view-type (eql :html-buffer))) 30 | (alexandria:when-let (html-buffer (get-buffer (preview-buffer-name buffer))) 31 | (let ((html (with-output-to-string (out) 32 | (yason:encode (render (buffer-text buffer)) 33 | out))) 34 | (window (pop-to-buffer html-buffer))) 35 | (lem-if:js-eval (lem:implementation) 36 | (window-view window) 37 | (format nil " 38 | const main = document.getElementById(\"main\"); 39 | main.innerHTML = ~A; 40 | " html))))) 41 | -------------------------------------------------------------------------------- /extensions/markdown-mode/preview/preview.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-markdown-mode/preview/preview 2 | (:use :cl :lem)) 3 | (in-package :lem-markdown-mode/preview/preview) 4 | 5 | (define-command markdown-preview () () 6 | (lem-markdown-mode/internal:preview (current-buffer) :html-buffer)) 7 | 8 | (defun render (string) 9 | (let ((3bmd-code-blocks:*code-blocks* t)) 10 | (with-output-to-string (stream) 11 | (3bmd:parse-string-and-print-to-stream string stream)))) 12 | -------------------------------------------------------------------------------- /extensions/nim-mode/lem-nim-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-nim-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "nim-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/nix-mode/indent.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-nix-mode/indent 2 | (:use :cl 3 | :lem 4 | :lem/language-mode) 5 | (:export :beginning-of-defun 6 | :end-of-defun 7 | :calc-indent)) 8 | (in-package :lem-nix-mode/indent) 9 | 10 | (defun beginning-of-defun (point n) 11 | (loop :repeat n :do (search-backward-regexp point "^\\{"))) 12 | 13 | (defun end-of-defun (point n) 14 | (if (minusp n) 15 | (beginning-of-defun point (- n)) 16 | (search-forward-regexp point "^\\}"))) 17 | 18 | (defun calc-indent (point) 19 | (with-point ((point point)) 20 | (let ((tab-width 2) 21 | (column (point-column point))) 22 | (+ column (- tab-width (rem column tab-width)))))) 23 | -------------------------------------------------------------------------------- /extensions/nix-mode/lem-nix-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-nix-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "indent") 5 | (:file "nix-mode"))) 6 | -------------------------------------------------------------------------------- /extensions/ocaml-mode/lem-ocaml-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-ocaml-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "ocaml-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/paredit-mode/lem-paredit-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-paredit-mode" 2 | :depends-on ("lem") 3 | :components ((:file "paredit-mode")) 4 | :in-order-to ((test-op (test-op "lem-paredit-mode/tests")))) 5 | 6 | (defsystem "lem-paredit-mode/tests" 7 | :depends-on ("lem" 8 | "lem-lisp-mode" 9 | "lem-lisp-syntax" 10 | "lem-paredit-mode" 11 | "rove" 12 | "cl-ppcre") 13 | :components 14 | ((:module "tests" 15 | :components 16 | ((:file "main")))) 17 | :perform (test-op (op c) (symbol-call :rove '#:run c))) -------------------------------------------------------------------------------- /extensions/patch-mode/lem-patch-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-patch-mode" 2 | :depends-on ("lem" 3 | "cl-ppcre") 4 | :serial t 5 | :components ((:file "patch-mode"))) 6 | -------------------------------------------------------------------------------- /extensions/patch-mode/patch-mode.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-patch-mode 2 | (:use :cl :lem :lem/language-mode) 3 | (:export :*patch-mode-hook* 4 | :patch-mode)) 5 | (in-package :lem-patch-mode) 6 | 7 | (define-attribute add-line-attribute 8 | (t :foreground :base0C)) 9 | 10 | (define-attribute delete-line-attribute 11 | (t :foreground :base08)) 12 | 13 | (define-attribute hunk-line-attribute 14 | (t :foreground :base06 :background :base01 :bold t)) 15 | 16 | (defun make-tmlanguage-patch () 17 | (let* ((patterns (make-tm-patterns 18 | (make-tm-match "^\\+.*$" :name 'add-line-attribute) 19 | (make-tm-match "^-.*$" :name 'delete-line-attribute) 20 | (make-tm-match "^\\@\\@ .*$" :name 'hunk-line-attribute)))) 21 | (make-tmlanguage :patterns patterns))) 22 | 23 | (defvar *patch-syntax-table* 24 | (let ((table (make-syntax-table))) 25 | (set-syntax-parser table (make-tmlanguage-patch)) 26 | table)) 27 | 28 | (define-major-mode patch-mode language-mode 29 | (:name "patch" 30 | :syntax-table *patch-syntax-table*) 31 | (setf (variable-value 'enable-syntax-highlight) t)) 32 | 33 | (define-file-type ("patch") patch-mode) 34 | -------------------------------------------------------------------------------- /extensions/posix-shell-mode/lem-posix-shell-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-posix-shell-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "posix-shell-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/process/lem-process.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-process" 2 | :depends-on ("async-process" "lem") 3 | :serial t 4 | :components ((:file "package") 5 | (:file "process") 6 | (:file "stream"))) 7 | -------------------------------------------------------------------------------- /extensions/process/package.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-process 2 | (:use :cl :lem) 3 | (:export :run-process 4 | :get-process-output-string 5 | :delete-process 6 | :process-alive-p 7 | :make-process-stream 8 | :process-send-input) 9 | #+sbcl 10 | (:lock t)) 11 | -------------------------------------------------------------------------------- /extensions/python-mode/lem-python-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-python-mode" 2 | :depends-on ("lem" 3 | #+#.(cl:if (asdf:find-system :async-process cl:nil) '(and) '(or)) "lem-process") 4 | :serial t 5 | :components ((:file "python-mode") 6 | #+#.(cl:if (asdf:find-system :async-process cl:nil) '(and) '(or)) 7 | (:file "run-python"))) 8 | -------------------------------------------------------------------------------- /extensions/review-mode/lem-review-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-review-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "review-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/ruby-mode/lem-ruby-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-ruby-mode" 2 | :depends-on ("lem" "lem-js-mode") 3 | :serial t 4 | :components ((:file "ruby-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/rust-mode/lem-rust-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-rust-mode" 2 | :depends-on ("lem" "lem-lisp-mode") 3 | :serial t 4 | :components ((:file "rust-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/scala-mode/lem-scala-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-scala-mode" 2 | :depends-on ("lem" "lem-js-mode") 3 | :serial t 4 | :components ((:file "scala-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/scheme-mode/errors.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-scheme-mode.errors 2 | (:use :cl) 3 | (:export :disconnected 4 | :change-connection)) 5 | (in-package :lem-scheme-mode.errors) 6 | 7 | (define-condition disconnected (simple-condition) 8 | ()) 9 | 10 | (define-condition change-connection (simple-condition) 11 | ()) 12 | -------------------------------------------------------------------------------- /extensions/scheme-mode/lem-scheme-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-scheme-mode" 2 | :depends-on ("alexandria" 3 | "trivial-types" 4 | "usocket" 5 | "trivia" 6 | "uiop" 7 | "swank" 8 | #+#.(cl:if (asdf:find-system :async-process cl:nil) '(and) '(or)) "lem-process" 9 | "lem") 10 | :serial t 11 | :components ((:file "syntax-data") 12 | (:file "syntax-indent") 13 | (:file "syntax-syntax-table") 14 | (:file "syntax-misc") 15 | (:file "syntax-parse") 16 | (:file "lem-scheme-syntax") 17 | (:file "errors") 18 | (:file "swank-protocol") 19 | (:file "package") 20 | (:file "grammar") 21 | (:file "scheme-mode") 22 | (:file "swank-connection") 23 | #+#.(cl:if (asdf:find-system :async-process cl:nil) '(and) '(or)) 24 | (:file "eval") 25 | (:file "repl"))) 26 | -------------------------------------------------------------------------------- /extensions/scheme-mode/lem-scheme-syntax.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-scheme-syntax 2 | (:use :cl) 3 | (:use-reexport 4 | :lem-scheme-syntax.data 5 | :lem-scheme-syntax.indent 6 | :lem-scheme-syntax.syntax-table 7 | :lem-scheme-syntax.misc 8 | :lem-scheme-syntax.parse)) 9 | -------------------------------------------------------------------------------- /extensions/scheme-mode/package.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-scheme-mode 2 | (:use :cl 3 | :lem 4 | :lem/completion-mode 5 | :lem/language-mode 6 | :lem-scheme-mode.errors 7 | :lem-scheme-mode.swank-protocol) 8 | (:export 9 | ;; scheme-mode.lisp 10 | :scheme-mode 11 | :*scheme-mode-keymap* 12 | :*scheme-mode-hook* 13 | :*use-scheme-process* 14 | :*scheme-run-command* 15 | :*scheme-load-command* 16 | :*use-scheme-slime* 17 | :*use-scheme-set-library* 18 | :*use-scheme-autodoc* 19 | :*scheme-swank-server-run-command* 20 | :*use-scheme-repl-shortcut* 21 | :*scheme-completion-names* 22 | :scheme-keyword-data 23 | :scheme-beginning-of-defun 24 | :scheme-end-of-defun 25 | :scheme-indent-sexp 26 | ;; swank-connection 27 | :scheme-slime-connect 28 | :scheme-slime 29 | ;; eval.lisp 30 | :scheme-kill-process 31 | ;; repl.lisp 32 | :scheme-repl-mode 33 | :scheme-repl-input-mode 34 | :*scheme-repl-mode-keymap* 35 | :*scheme-repl-input-mode-keymap* 36 | :start-scheme-repl 37 | :scheme-switch-to-repl-buffer 38 | :scheme-eval-or-newline 39 | :scheme-eval-last-expression 40 | :scheme-eval-region 41 | :scheme-load-file 42 | :scheme-repl-shortcut)) 43 | -------------------------------------------------------------------------------- /extensions/scheme-mode/syntax-misc.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-scheme-syntax.misc 2 | (:use :cl :lem) 3 | (:export 4 | :beginning-of-defun 5 | :top-of-defun)) 6 | (in-package :lem-scheme-syntax.misc) 7 | 8 | (defun beginning-of-defun (point n) 9 | (with-point ((start point)) 10 | (if (minusp n) 11 | (dotimes (_ (- n) point) 12 | (if (start-line-p point) 13 | (line-offset point -1) 14 | (line-start point)) 15 | (loop 16 | (when (char= #\( (character-at point 0)) 17 | (return)) 18 | (unless (line-offset point -1) 19 | (move-point point start) 20 | (return-from beginning-of-defun nil)))) 21 | (dotimes (_ n point) 22 | (loop 23 | (unless (line-offset point 1) 24 | (move-point point start) 25 | (return-from beginning-of-defun nil)) 26 | (when (char= #\( (character-at point 0)) 27 | (return))))))) 28 | 29 | (defun top-of-defun (point) 30 | (beginning-of-defun (line-end point) -1)) 31 | -------------------------------------------------------------------------------- /extensions/scheme-mode/syntax-syntax-table.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-scheme-syntax.syntax-table 2 | (:use :cl :lem) 3 | (:export :*syntax-table*)) 4 | (in-package :lem-scheme-syntax.syntax-table) 5 | 6 | (flet ((f (c1 c2 step-fn) 7 | (when c1 8 | (when (and (member c1 '(#\#)) 9 | (or (alphanumericp c2) 10 | (member c2 '(#\+ #\-)))) 11 | (funcall step-fn))))) 12 | 13 | (defun skip-expr-prefix-forward (point) 14 | (f (character-at point 0) 15 | (character-at point 1) 16 | (lambda () 17 | (character-offset point 2)))) 18 | 19 | (defun skip-expr-prefix-backward (point) 20 | (f (character-at point -2) 21 | (character-at point -1) 22 | (lambda () 23 | (character-offset point -2))))) 24 | 25 | (defvar *syntax-table* 26 | (make-syntax-table 27 | :space-chars '(#\space #\tab #\newline) 28 | :symbol-chars '(#\! #\$ #\% #\& #\* #\/ #\: #\< #\= #\> #\? #\^ #\_ #\~ 29 | #\+ #\- #\. #\@) 30 | :paren-pairs '((#\( . #\)) 31 | (#\[ . #\]) 32 | (#\{ . #\})) 33 | :string-quote-chars '(#\") 34 | :escape-chars '(#\\) 35 | :fence-chars '(#\|) 36 | :expr-prefix-chars '(#\' #\, #\@ #\# #\`) 37 | :expr-prefix-forward-function 'skip-expr-prefix-forward 38 | :expr-prefix-backward-function 'skip-expr-prefix-backward 39 | :line-comment-string ";" 40 | :block-comment-pairs '(("#|" . "|#")))) 41 | -------------------------------------------------------------------------------- /extensions/shell-mode/lem-shell-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-shell-mode" 2 | :depends-on ("lem" "lem-process" "lem-lisp-mode") 3 | :serial t 4 | :components ((:file "shell-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/sql-mode/lem-sql-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-sql-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "sql-mode"))) 5 | -------------------------------------------------------------------------------- /extensions/swift-mode/lem-swift-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-swift-mode" 2 | :depends-on ("lem" "yason" "lem-lsp-mode") 3 | :serial t 4 | :components ((:file "swift-mode") (:file "lsp-config"))) 5 | -------------------------------------------------------------------------------- /extensions/swift-mode/lsp-config.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-swift-mode/lsp-config 2 | (:use :cl :lem-lsp-mode :lem-lsp-base/type)) 3 | 4 | (in-package :lem-swift-mode/lsp-config) 5 | 6 | (define-language-spec (swift-spec lem-swift-mode:swift-mode) 7 | :language-id "swift" 8 | :root-uri-patterns '("Package.swift") 9 | :command '("xcrun" "--toolchain" "swift" "sourcekit-lsp") ;; either behind $PATH or 'xcrun --toolchain swift sourcekit-lsp' 10 | :install-command "" ;; It kinda..has to be installed? 11 | :readme-url "https://github.com/apple/sourcekit-lsp" 12 | :connection-mode :stdio) -------------------------------------------------------------------------------- /extensions/swift-mode/swift-mode.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-swift-mode 2 | (:use :cl :lem :lem/completion-mode :lem/language-mode) 3 | (:import-from :lem/tmlanguage :load-tmlanguage) 4 | (:export :*swift-mode-hook* :swift-mode)) 5 | 6 | (in-package :lem-swift-mode) 7 | 8 | ;; Syntax highlighting (like the go implementation) is effectively 9 | ;; a json file from Atom's system. Eventually, I will have to 10 | ;; update the json for Swift 5.9's macros and new syntax 11 | (defvar *swift-syntax-table* 12 | (let ((table (make-syntax-table 13 | :space-chars '(#\space #\tab #\newline) 14 | :symbol-chars '(#\_) 15 | :paren-pairs '((#\( . #\)) 16 | (#\{ . #\}) 17 | (#\[ . #\])) 18 | :string-quote-chars '(#\" #\#) 19 | :line-comment-string "//" 20 | :block-comment-pairs '(("/*" . "*/")))) 21 | (tmlanguage (load-tmlanguage 22 | (merge-pathnames "swift.json" 23 | (asdf:system-source-directory :lem-swift-mode))))) 24 | (set-syntax-parser table tmlanguage) 25 | table)) 26 | 27 | (define-major-mode swift-mode language-mode 28 | (:name "Swift" 29 | :keymap *swfit-mode-keymap* 30 | :syntax-table *swift-syntax-table* 31 | :mode-hook *swift-mode-hook*) 32 | (setf (variable-value 'enable-syntax-highlight) t) 33 | (setf (variable-value 'tab-width) 2) ;; Can be 4, Swift OSS is 2 34 | (setf (variable-value 'line-comment) "//") 35 | (setf (variable-value 'insertion-line-comment) "// ")) 36 | 37 | (define-file-type ("swift") swift-mode) 38 | -------------------------------------------------------------------------------- /extensions/terminal/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | RUN apt-get update && apt-get install -y \ 3 | build-essential curl libtool \ 4 | && apt-get clean \ 5 | && rm -rf /var/lib/apt/lists/* 6 | RUN cd /tmp \ 7 | && curl -O https://www.leonerd.org.uk/code/libvterm/libvterm-0.3.3.tar.gz \ 8 | && tar xf libvterm-0.3.3.tar.gz \ 9 | && cd /tmp/libvterm-0.3.3 \ 10 | && export CXXFLAGS="$CXXFLAGS -fPIC" \ 11 | && export CFLAGS="$CFLAGS -fPIC" make \ 12 | && make install clean \ 13 | && rm -rf /tmp/libvterm-0.3.3 14 | #docker build . -t libvterm && docker run -v $PWD:/build --rm libvterm /bin/bash -c "cd /build/;gcc terminal.c -Wl,-Bstatic -lvterm -Wl,-Bdynamic -o terminal.so -shared -fPIC -lutil" 15 | -------------------------------------------------------------------------------- /extensions/terminal/Dockerfile.musl: -------------------------------------------------------------------------------- 1 | FROM alpine:3.17 2 | RUN apk add --no-cache alpine-sdk curl-dev libtool 3 | RUN cd /tmp \ 4 | && curl -O https://www.leonerd.org.uk/code/libvterm/libvterm-0.3.3.tar.gz \ 5 | && tar xf libvterm-0.3.3.tar.gz \ 6 | && cd /tmp/libvterm-0.3.3 \ 7 | && export CXXFLAGS="$CXXFLAGS -fPIC" \ 8 | && export CFLAGS="$CFLAGS -fPIC" make \ 9 | && make install clean \ 10 | && rm -rf /tmp/libvterm-0.3.3 11 | #docker build . -t libvterm && docker run -v $PWD:/build --rm libvterm /bin/ash -c "cd /build/;gcc terminal.c -Wl,-Bstatic -lvterm -Wl,-Bdynamic -o terminal.so -shared -fPIC" 12 | -------------------------------------------------------------------------------- /extensions/terminal/lem-terminal.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-terminal" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "ffi") 5 | (:file "terminal") 6 | (:file "terminal-mode"))) 7 | -------------------------------------------------------------------------------- /extensions/terminal/lib/linux/x64/terminal.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/extensions/terminal/lib/linux/x64/terminal.so -------------------------------------------------------------------------------- /extensions/terminal/lib/macosx/arm64/terminal.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/extensions/terminal/lib/macosx/arm64/terminal.so -------------------------------------------------------------------------------- /extensions/terraform-mode/lem-terraform-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-terraform-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "indent") 5 | (:file "terraform-mode") 6 | (:file "lsp-config"))) 7 | -------------------------------------------------------------------------------- /extensions/terraform-mode/lsp-config.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-terraform-mode/lsp-config 2 | (:use :cl 3 | :lem-lsp-mode 4 | :lem-lsp-base/type)) 5 | (in-package :lem-terraform-mode/lsp-config) 6 | 7 | (define-language-spec (terraform-spec lem-terraform-mode:terraform-mode) 8 | :language-id "terraform" 9 | :root-uri-patterns '() 10 | :command (lambda (port) `("terraform-ls" "serve" "-port" ,(princ-to-string port))) 11 | :install-command "" 12 | :readme-url "https://github.com/hashicorp/terraform-ls" 13 | :connection-mode :tcp) 14 | -------------------------------------------------------------------------------- /extensions/typescript-mode/lem-typescript-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-typescript-mode" 2 | :depends-on ("lem" "lem-lsp-mode" "lem-js-mode") 3 | :serial t 4 | :components ((:file "typescript-mode") 5 | (:file "lsp-config"))) 6 | -------------------------------------------------------------------------------- /extensions/typescript-mode/lsp-config.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-typescript-mode/lsp-config 2 | (:use :cl)) 3 | (in-package :lem-typescript-mode/lsp-config) 4 | 5 | (lem-lsp-mode:define-language-spec (typescript-spec lem-typescript-mode:typescript-mode) 6 | :language-id "typescript" 7 | :root-uri-patterns '("package.json" "tsconfig.json") 8 | :command '("typescript-language-server" "--stdio") 9 | :install-command "npm install -g typescript-language-server typescript" 10 | :readme-url "https://github.com/typescript-language-server/typescript-language-server" 11 | :connection-mode :stdio) 12 | -------------------------------------------------------------------------------- /extensions/typescript-mode/typescript-mode.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-typescript-mode 2 | (:use :cl 3 | :lem 4 | :lem/language-mode 5 | :lem/language-mode-tools) 6 | (:export :typescript-mode)) 7 | (in-package :lem-typescript-mode) 8 | 9 | (define-major-mode typescript-mode lem/language-mode:language-mode 10 | (:name "TypeScript" 11 | :keymap *typescript-mode-keymap* 12 | :syntax-table lem-js-mode::*js-syntax-table* 13 | :mode-hook *typescript-mode-hook* 14 | :formatter 'lem-js-mode::prettier) 15 | (setf (variable-value 'enable-syntax-highlight) t 16 | (variable-value 'indent-tabs-mode) nil 17 | (variable-value 'tab-width) 2 18 | (variable-value 'calc-indent-function) 'lem-js-mode::js-calc-indent 19 | (variable-value 'line-comment) "//" 20 | (variable-value 'beginning-of-defun-function) 'lem-js-mode::beginning-of-defun 21 | (variable-value 'end-of-defun-function) 'lem-js-mode::end-of-defun)) 22 | 23 | (define-file-type ("ts" "tsx") typescript-mode) 24 | -------------------------------------------------------------------------------- /extensions/vi-mode/leader.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-vi-mode/leader 2 | (:use :cl 3 | :lem) 4 | (:import-from :lem-vi-mode/core 5 | :vi-keymap) 6 | (:export :leader-key)) 7 | (in-package :lem-vi-mode/leader) 8 | 9 | (define-named-key "Leader") 10 | 11 | (define-editor-variable leader-key "\\") 12 | 13 | (defun mapleader-key () 14 | (first (lem-core::parse-keyspec (variable-value 'leader-key)))) 15 | 16 | (defun mapleader-key-p (key) 17 | (eq key (mapleader-key))) 18 | 19 | (defun leader-key () 20 | (make-key :sym "Leader")) 21 | 22 | (defmethod keymap-find-keybind ((keymap vi-keymap) (key lem-core::key) cmd) 23 | (if (mapleader-key-p key) 24 | (call-next-method keymap (leader-key) cmd) 25 | (call-next-method))) 26 | 27 | (defmethod keymap-find-keybind ((keymap vi-keymap) (key cons) cmd) 28 | (if (mapleader-key-p (first key)) 29 | (call-next-method keymap (cons (leader-key) (rest key)) cmd) 30 | (call-next-method))) 31 | -------------------------------------------------------------------------------- /extensions/vi-mode/rc-example.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-user) 2 | 3 | ;;; vi-mode 4 | (define-key lem-vi-mode:*normal-keymap* "q" 'quit-active-window) 5 | (define-key lem-vi-mode:*insert-keymap* "C-n" 'lem/abbrev:abbrev-with-pop-up-window) 6 | 7 | (add-hook lem-vi-mode:*enable-hook* 8 | (lambda () 9 | (message "enable"))) 10 | 11 | (add-hook lem-vi-mode:*disable-hook* 12 | (lambda () 13 | (message "disable"))) 14 | 15 | (lem-vi-mode:define-ex-command "load" (range argument) 16 | (declare (ignore range)) 17 | (let ((filename (string-trim " " argument))) 18 | (lem-lisp-mode:lisp-load-file (if (string= filename "") 19 | (buffer-filename (current-buffer)) 20 | filename)))) 21 | -------------------------------------------------------------------------------- /extensions/vi-mode/special-binds.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-vi-mode/special-binds 2 | (:use :cl) 3 | (:import-from :lem-vi-mode/core 4 | :mode-specific-keymaps) 5 | (:import-from :lem/directory-mode 6 | :directory-mode 7 | :*directory-mode-keymap*) 8 | (:import-from :lem-lisp-mode/sldb 9 | :sldb-mode 10 | :*sldb-keymap*) 11 | (:import-from :lem-lisp-mode/inspector 12 | :lisp-inspector-mode 13 | :*lisp-inspector-keymap*)) 14 | (in-package :lem-vi-mode/special-binds) 15 | 16 | (defmethod mode-specific-keymaps ((mode directory-mode)) 17 | (list *directory-mode-keymap*)) 18 | 19 | (defmethod mode-specific-keymaps ((mode sldb-mode)) 20 | (list *sldb-keymap*)) 21 | 22 | (defmethod mode-specific-keymaps ((mode lisp-inspector-mode)) 23 | (list *lisp-inspector-keymap*)) 24 | -------------------------------------------------------------------------------- /extensions/welcome/lem-welcome.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-welcome" 2 | :depends-on (:lem :lem-vi-mode) 3 | :serial t 4 | :components ((:file "welcome"))) 5 | -------------------------------------------------------------------------------- /extensions/xml-mode/lem-xml-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-xml-mode" 2 | :depends-on ("lem" 3 | "cl-ppcre") 4 | :serial t 5 | :components ((:file "xml-mode"))) 6 | -------------------------------------------------------------------------------- /extensions/yaml-mode/lem-yaml-mode.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-yaml-mode" 2 | :depends-on ("lem") 3 | :serial t 4 | :components ((:file "yaml-mode"))) 5 | -------------------------------------------------------------------------------- /frontends/fake-interface/lem-fake-interface.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-fake-interface" 2 | :depends-on ("lem" "lem/extensions") 3 | :serial t 4 | :components ((:file "fake-interface"))) 5 | -------------------------------------------------------------------------------- /frontends/ncurses/config.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-ncurses/config 2 | (:use :cl 3 | :lem) 4 | (:export :escape-delay)) 5 | (in-package :lem-ncurses/config) 6 | 7 | ;; escape key delay setting 8 | (define-editor-variable escape-delay 100) 9 | -------------------------------------------------------------------------------- /frontends/ncurses/drawing-object.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-ncurses/drawing-object 2 | (:use :cl 3 | :lem-core/display) 4 | (:export :object-width 5 | :object-height)) 6 | (in-package :lem-ncurses/drawing-object) 7 | 8 | (defgeneric object-width (drawing-object)) 9 | 10 | (defmethod object-width ((drawing-object void-object)) 11 | 0) 12 | 13 | (defmethod object-width ((drawing-object text-object)) 14 | (lem-core:string-width (text-object-string drawing-object))) 15 | 16 | (defmethod object-width ((drawing-object eol-cursor-object)) 17 | 0) 18 | 19 | (defmethod object-width ((drawing-object extend-to-eol-object)) 20 | 0) 21 | 22 | (defmethod object-width ((drawing-object line-end-object)) 23 | (lem-core:string-width (text-object-string drawing-object))) 24 | 25 | (defmethod object-width ((drawing-object image-object)) 26 | 0) 27 | 28 | (defmethod object-height (drawing-object) 29 | 1) 30 | -------------------------------------------------------------------------------- /frontends/ncurses/lem-ncurses.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-ncurses" 2 | :depends-on ("cffi" 3 | "cl-charms" 4 | "cl-setlocale" 5 | "lem" 6 | "lem/extensions") 7 | :serial t 8 | :components (#+pdcurses(:file "cl-charms-pdcurseswin32") 9 | (:file "config") 10 | (:file "term") 11 | (:file "clipboard") 12 | (:file "style") 13 | (:file "key") 14 | (:file "attribute") 15 | (:file "drawing-object") 16 | (:file "view") 17 | (:file "render") 18 | (:file "input") 19 | (:file "mainloop") 20 | (:file "ncurses"))) 21 | -------------------------------------------------------------------------------- /frontends/pdcurses/lem-pdcurses.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-pdcurses" 2 | :depends-on ("lem-ncurses") 3 | :serial t 4 | :components (#+win32(:file "ncurses-pdcurseswin32"))) 5 | -------------------------------------------------------------------------------- /frontends/sdl2/README.md: -------------------------------------------------------------------------------- 1 | ## Install 2 | ### Ubuntu 3 | 4 | ```shell 5 | $ sudo apt install libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev 6 | ``` 7 | 8 | ### MacOS 9 | 10 | ```shell 11 | $ brew install sdl2 12 | $ brew install sdl2_image 13 | $ brew install sdl2_ttf 14 | ``` 15 | 16 | ### Windows 17 | #### Requirements 18 | - msys2 19 | - sbcl 20 | - [OpenSSL v1.1.1](https://slproweb.com/products/Win32OpenSSL.html) 21 | 22 | ```shell 23 | $ pacman -S mingw-w64-x86_64-roswell 24 | 25 | $ pacman -S mingw-w64-x86_64-SDL2 26 | $ pacman -S mingw-w64-x86_64-SDL2_image 27 | $ pacman -S mingw-w64-x86_64-SDL2_ttf 28 | ``` 29 | 30 | ## Launch 31 | ```shell 32 | $ qlot install 33 | $ qlot exec sbcl 34 | ``` 35 | 36 | ```common-lisp 37 | * (ql:quickload :lem-sdl2) 38 | * (lem:lem) 39 | ``` 40 | 41 | #### Keyboard Layout (Windows / Mac OS) 42 | 43 | If your keyboard is a JIS layout, you need to put the following settings in $HOME/.lem/init.lisp 44 | 45 | ```common-lisp 46 | #+lem-sdl2 47 | (lem-sdl2:set-keyboard-layout :jis) 48 | ``` 49 | -------------------------------------------------------------------------------- /frontends/sdl2/icon-font.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-sdl2/icon-font 2 | (:use :cl) 3 | (:export :clear-icon-font-cache 4 | :icon-font)) 5 | (in-package :lem-sdl2/icon-font) 6 | 7 | (defvar *icon-font-cache* (make-hash-table :test 'eql)) 8 | 9 | (defun clear-icon-font-cache () 10 | (clrhash *icon-font-cache*)) 11 | 12 | (defun icon-font (character font-size) 13 | ;; TODO: Fix problem with opening several of the same font file 14 | (or (gethash character *icon-font-cache*) 15 | (alexandria:when-let (font-name (lem:icon-value (char-code character) :font)) 16 | (let ((pathname (lem-sdl2/resource:get-resource-pathname 17 | (merge-pathnames font-name "resources/fonts/")))) 18 | (setf (gethash character *icon-font-cache*) 19 | (sdl2-ttf:open-font pathname font-size)))))) 20 | -------------------------------------------------------------------------------- /frontends/sdl2/lem-sdl2.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-sdl2" 2 | :depends-on ("sdl2" 3 | "sdl2-ttf" 4 | "sdl2-image" 5 | "lem" 6 | "lem/extensions" 7 | "trivial-main-thread") 8 | :serial t 9 | :components ((:file "wm") 10 | (:file "resource") 11 | (:file "platform") 12 | (:file "keyboard") 13 | (:file "font") 14 | (:file "icon") 15 | (:file "text-surface-cache") 16 | (:file "log") 17 | (:file "sdl2") 18 | (:file "icon-font") 19 | (:file "mouse") 20 | (:file "utils") 21 | (:file "display") 22 | (:file "view") 23 | (:file "main") 24 | (:file "drawing") 25 | (:file "graphics") 26 | (:file "image-buffer") 27 | (:file "tree") 28 | (:file "color-picker"))) 29 | 30 | (defsystem "lem-sdl2/executable" 31 | :build-operation program-op 32 | :build-pathname "../../lem" 33 | :entry-point "lem:main" 34 | :depends-on ("lem-sdl2")) 35 | -------------------------------------------------------------------------------- /frontends/sdl2/log.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-sdl2/log 2 | (:use :cl) 3 | (:export :do-log 4 | :with-debug)) 5 | (in-package :lem-sdl2/log) 6 | 7 | (defun do-log (value) 8 | (let ((log-file (merge-pathnames "logs/error.log" (lem:lem-home)))) 9 | (ensure-directories-exist log-file) 10 | (with-open-file (out log-file 11 | :direction :output 12 | :if-exists :append 13 | :if-does-not-exist :create) 14 | (uiop:println value out)))) 15 | 16 | (defun call-with-debug (log-function body-function) 17 | (funcall log-function) 18 | (handler-bind ((error (lambda (e) 19 | (log:info "~A" 20 | (with-output-to-string (out) 21 | (format out "~A~%" e) 22 | (uiop:print-backtrace :condition e :stream out)))))) 23 | (funcall body-function))) 24 | 25 | (defmacro with-debug ((&rest args) &body body) 26 | `(call-with-debug (lambda () (log:debug ,@args)) 27 | (lambda () ,@body))) 28 | -------------------------------------------------------------------------------- /frontends/sdl2/mouse.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-sdl2/mouse 2 | (:use :cl) 3 | (:export :cursor-shown-p 4 | :show-cursor 5 | :hide-cursor)) 6 | (in-package :lem-sdl2/mouse) 7 | 8 | (defvar *cursor-shown* t) 9 | 10 | (defun cursor-shown-p () 11 | *cursor-shown*) 12 | 13 | (defun show-cursor () 14 | (setf *cursor-shown* t) 15 | (sdl2:show-cursor)) 16 | 17 | (defun hide-cursor () 18 | (setf *cursor-shown* nil) 19 | (sdl2:hide-cursor)) 20 | -------------------------------------------------------------------------------- /frontends/sdl2/platform.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-sdl2/platform 2 | (:use :cl) 3 | (:export :platform 4 | :linux 5 | :mac 6 | :windows 7 | :get-platform)) 8 | (in-package :lem-sdl2/platform) 9 | 10 | (defclass platform () ()) 11 | (defclass linux (platform) ()) 12 | (defclass windows (platform) ()) 13 | (defclass mac (platform) ()) 14 | 15 | (defvar *platform* nil) 16 | 17 | (defun get-platform () 18 | (or *platform* 19 | (setf *platform* 20 | (let ((platform-name (sdl2:platform))) 21 | (alexandria:switch (platform-name :test #'equal) 22 | ("Windows" 23 | (make-instance 'windows)) 24 | ("Mac OS X" 25 | (make-instance 'mac)) 26 | (otherwise 27 | (make-instance 'linux))))))) 28 | -------------------------------------------------------------------------------- /frontends/sdl2/resource.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-sdl2/resource 2 | (:use :cl) 3 | (:export :get-resource-pathname)) 4 | (in-package :lem-sdl2/resource) 5 | 6 | (defvar *resource-directory* nil) 7 | 8 | (defun get-resource-pathname (pathname) 9 | (if *resource-directory* 10 | (merge-pathnames pathname *resource-directory*) 11 | (or (lem:lem-relative-pathname pathname) 12 | (asdf:system-relative-pathname :lem-sdl2 pathname)))) 13 | -------------------------------------------------------------------------------- /frontends/sdl2/resources/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/folder.png -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/FreeMono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/FreeMono.ttf -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/NotoColorEmoji.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/NotoColorEmoji.ttf -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/NotoSansCJK-Bold.ttc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/NotoSansCJK-Bold.ttc -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/NotoSansCJK-Regular.ttc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/NotoSansCJK-Regular.ttc -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/NotoSansMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/NotoSansMono-Bold.ttf -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/NotoSansMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/NotoSansMono-Regular.ttf -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/all-the-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/all-the-icons.ttf -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/file-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/file-icons.ttf -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/fontawesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/fontawesome.ttf -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/material-design-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/material-design-icons.ttf -------------------------------------------------------------------------------- /frontends/sdl2/resources/fonts/octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/fonts/octicons.ttf -------------------------------------------------------------------------------- /frontends/sdl2/resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/icon.png -------------------------------------------------------------------------------- /frontends/sdl2/resources/open-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/frontends/sdl2/resources/open-folder.png -------------------------------------------------------------------------------- /frontends/sdl2/sdl2.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-sdl2/sdl2 2 | (:use :cl) 3 | (:export :sdl2)) 4 | (in-package :lem-sdl2/sdl2) 5 | 6 | (defclass sdl2 (lem:implementation) 7 | () 8 | (:default-initargs 9 | :name :sdl2 10 | :redraw-after-modifying-floating-window nil)) 11 | 12 | (setf (lem-core:variable-value 'lem-core:highlight-line :global) t) 13 | 14 | (pushnew :lem-sdl2 *features*) 15 | -------------------------------------------------------------------------------- /frontends/sdl2/text-surface-cache.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-sdl2/text-surface-cache 2 | (:use :cl) 3 | (:export :clear-text-surface-cache 4 | :get-text-surface-cache 5 | :register-text-surface-cache)) 6 | (in-package :lem-sdl2/text-surface-cache) 7 | 8 | (defvar *text-surface-cache* (make-hash-table :test 'equal)) 9 | 10 | (defstruct cache-entry 11 | type 12 | attribute 13 | surface) 14 | 15 | (defun clear-text-surface-cache () 16 | (clrhash *text-surface-cache*)) 17 | 18 | (defun get-text-surface-cache (string attribute type) 19 | (dolist (entry (gethash string *text-surface-cache*)) 20 | (when (and (lem-core:attribute-equal attribute (cache-entry-attribute entry)) 21 | (eq type (cache-entry-type entry))) 22 | (return (cache-entry-surface entry))))) 23 | 24 | (defun register-text-surface-cache (string attribute type surface) 25 | (push (make-cache-entry 26 | :type type 27 | :attribute attribute 28 | :surface surface) 29 | (gethash string *text-surface-cache*))) 30 | -------------------------------------------------------------------------------- /frontends/sdl2/utils.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-sdl2/utils 2 | (:use :cl) 3 | (:export :create-texture 4 | :render-texture)) 5 | (in-package :lem-sdl2/utils) 6 | 7 | (defun create-texture (renderer width height) 8 | (sdl2:create-texture renderer 9 | sdl2:+pixelformat-rgba8888+ 10 | sdl2-ffi:+sdl-textureaccess-target+ 11 | width 12 | height)) 13 | 14 | (defun render-texture (renderer texture x y width height) 15 | (sdl2:with-rects ((dest-rect x y width height)) 16 | (sdl2:render-copy-ex renderer 17 | texture 18 | :source-rect nil 19 | :dest-rect dest-rect 20 | :flip (list :none)))) 21 | -------------------------------------------------------------------------------- /frontends/sdl2/wm.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-sdl2/wm 2 | (:use :cl) 3 | (:export :set-x11-wm-class)) 4 | (in-package :lem-sdl2/wm) 5 | 6 | (defparameter +lem-x11-wm-class+ "Lem SDL2") 7 | 8 | ;; this is SDL2 way 9 | ;; if the stable version of SDL is 3, set WM_CLASS is set via hint SDL_HINT_APP_ID 10 | ;; 11 | ;; cf. 12 | ;; - how SDL3 gets WM_CLASS: 13 | ;; - https://github.com/libsdl-org/SDL/blob/d3f2de7f297d761a7dc5b0dda3c7b5d7bd49eac9/src/video/x11/SDL_x11window.c#L633C40-L633C40 14 | ;; - how to set WM_CLASS in here: 15 | ;; - SDL_SetHint() function with key SDL_HINT_APP_ID 16 | ;; - https://wiki.libsdl.org/SDL2/SDL_SetHint 17 | ;; - https://github.com/libsdl-org/SDL/blob/d3f2de7f297d761a7dc5b0dda3c7b5d7bd49eac9/src/core/unix/SDL_appid.c#L63C45-L63C45 18 | (defun set-x11-wm-class () 19 | (setf (uiop:getenv "SDL_VIDEO_X11_WMCLASS") +lem-x11-wm-class+)) 20 | -------------------------------------------------------------------------------- /frontends/server/config.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (setf lem-markdown-mode/internal::*view-type* :html-buffer) 4 | -------------------------------------------------------------------------------- /frontends/server/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | #dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /frontends/server/frontend/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Lem 7 | 8 | 9 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /frontends/server/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Lem 7 | 8 | 9 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /frontends/server/frontend/main.js: -------------------------------------------------------------------------------- 1 | import { Editor } from './editor.js'; 2 | 3 | const canvas = document.querySelector('#editor'); 4 | 5 | function main() { 6 | document.fonts.ready.then(() => { 7 | const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'; 8 | const editor = new Editor({ 9 | canvas: canvas, 10 | fontName: 'Monospace', 11 | fontSize: 19, 12 | onLoaded: null, 13 | url: `${protocol}://${window.location.hostname}:${window.location.port}`, 14 | onExit: null, 15 | onClosed: null, 16 | onRestart: null, 17 | onUserInput: null, 18 | }); 19 | 20 | editor.init(); 21 | }); 22 | } 23 | 24 | main(); 25 | -------------------------------------------------------------------------------- /frontends/server/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "editor", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "vite": "^5.2.14" 13 | }, 14 | "dependencies": { 15 | "json-rpc-2.0": "^1.7.0", 16 | "meaw": "^8.0.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontends/server/jsonrpc-stdio-patch.lisp: -------------------------------------------------------------------------------- 1 | (in-package :jsonrpc/transport/stdio) 2 | 3 | (defmethod send-message-using-transport ((transport stdio-transport) connection message) 4 | (let ((json (babel:string-to-octets 5 | (with-output-to-string (s) 6 | (yason:encode message s)))) 7 | (stream (connection-socket connection))) 8 | (format stream "Content-Length: ~A~C~C~:*~:*~C~C" 9 | (length json) 10 | #\Return 11 | #\Newline) 12 | (write-sequence json stream) 13 | (force-output stream))) 14 | 15 | (defmethod receive-message-using-transport ((transport stdio-transport) connection) 16 | (let* ((stream (connection-socket connection)) 17 | (headers (read-headers stream)) 18 | (length (ignore-errors (parse-integer (gethash "content-length" headers))))) 19 | (when length 20 | (let ((body 21 | (with-output-to-string (out) 22 | (loop 23 | :for c := (read-char stream) 24 | :do (write-char c out) 25 | (decf length (babel:string-size-in-octets (string c))) 26 | (when (<= length 0) 27 | (return)))))) 28 | (parse-message body))))) 29 | -------------------------------------------------------------------------------- /frontends/server/lem-server.asd: -------------------------------------------------------------------------------- 1 | (defsystem "lem-server" 2 | :depends-on ("lem" 3 | "lem/extensions" 4 | "jsonrpc" 5 | "jsonrpc/transport/stdio" 6 | "jsonrpc/transport/websocket" 7 | "jsonrpc/transport/local-domain-socket" 8 | "command-line-arguments") 9 | :serial t 10 | :components ((:file "jsonrpc-stdio-patch") 11 | (:file "config") 12 | (:file "utils") 13 | (:file "view") 14 | (:file "mouse") 15 | (:file "main"))) 16 | -------------------------------------------------------------------------------- /frontends/server/mouse.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem-server/mouse 2 | (:use :cl) 3 | (:export :update-position 4 | :get-position)) 5 | (in-package :lem-server/mouse) 6 | 7 | (defvar *mouse-x* 0) 8 | (defvar *mouse-y* 0) 9 | 10 | (defun update-position (x y) 11 | (setf *mouse-x* x 12 | *mouse-y* y)) 13 | 14 | (defun get-position () 15 | (values *mouse-x* *mouse-y*)) 16 | -------------------------------------------------------------------------------- /frontends/server/utils.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-server/utils 2 | (:use :cl) 3 | (:export :hash 4 | :with-error-handler 5 | :json-equal 6 | :pretty-json)) 7 | (in-package :lem-server/utils) 8 | 9 | (defun hash (&rest args) 10 | (alexandria:plist-hash-table args :test #'equal)) 11 | 12 | (defmacro with-error-handler (() &body body) 13 | `(handler-case 14 | (handler-bind ((error (lambda (c) 15 | (log:info "~A" 16 | (with-output-to-string (stream) 17 | (format stream "~A~%" c) 18 | (uiop:print-backtrace :stream stream 19 | :condition c) 20 | (force-output stream)))))) 21 | ,@body) 22 | (error ()))) 23 | 24 | (defun json-equal (x y) 25 | (string= (with-output-to-string (out) (yason:encode x out)) 26 | (with-output-to-string (out) (yason:encode y out)))) 27 | 28 | (defun pretty-json (value) 29 | (with-output-to-string (out) 30 | (yason:encode value 31 | (yason:make-json-output-stream out)))) 32 | -------------------------------------------------------------------------------- /qlfile: -------------------------------------------------------------------------------- 1 | ql uiop 2 | git micros https://github.com/lem-project/micros.git 3 | git lem-mailbox https://github.com/lem-project/lem-mailbox.git 4 | git async-process https://github.com/lem-project/async-process.git 5 | git sblint https://github.com/cxxxr/sblint.git 6 | git rove https://github.com/fukamachi/rove.git 7 | git cl-sdl2 https://github.com/lem-project/cl-sdl2.git 8 | git cl-sdl2-ttf https://github.com/lem-project/cl-sdl2-ttf.git 9 | git cl-sdl2-image https://github.com/lem-project/cl-sdl2-image.git 10 | git jsonrpc https://github.com/cxxxr/jsonrpc.git 11 | -------------------------------------------------------------------------------- /roswell/lem-language-server.ros: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #|-*- mode:lisp -*-|# 3 | #| 4 | exec ros +Q -- $0 "$@" 5 | |# 6 | (progn ;;init forms 7 | (ros:ensure-asdf) 8 | (uiop:with-current-directory ((asdf:system-source-directory :lem)) 9 | (setf (uiop:getenv "SBCL_HOME") "") 10 | (uiop:run-program '("qlot" "install" "--no-deps") 11 | :output t 12 | :error-output t) 13 | #+quicklisp 14 | (setf ql:*quicklisp-home* 15 | (merge-pathnames #P".qlot/")) 16 | (load (merge-pathnames #P".qlot/setup.lisp"))) 17 | (uiop:symbol-call :ql :quickload '(:lem-language-server/cli) :silent t)) 18 | 19 | (defpackage :ros.script.lem-language-server.3881471585 20 | (:use :cl)) 21 | (in-package :ros.script.lem-language-server.3881471585) 22 | 23 | (defun main (&rest args) 24 | (lem-language-server/cli:main args)) 25 | 26 | ;;; vim: set ft=lisp lisp: 27 | -------------------------------------------------------------------------------- /roswell/lem-ncurses-ccl.ros: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #|-*- mode:lisp -*-|# 3 | #| lem simple emacs clone 4 | exec ros +Q -L ccl-bin -- $0 "$@" 5 | |# 6 | (progn 7 | (ros:ensure-asdf) 8 | (uiop:with-current-directory ((asdf:system-source-directory :lem)) 9 | (setf (uiop:getenv "SBCL_HOME") "") 10 | (uiop:run-program '("qlot" "install" "--no-deps") 11 | :output t 12 | :error-output t) 13 | #+quicklisp 14 | (setf ql:*quicklisp-home* 15 | (merge-pathnames #P".qlot/")) 16 | (load (merge-pathnames #P".qlot/setup.lisp"))) 17 | (uiop:symbol-call :ql :quickload :lem-ncurses :silent t) 18 | (uiop:symbol-call :lem-core :load-site-init)) 19 | 20 | (defpackage :ros.script.lem-ncurses-ccl.3724915314 21 | (:use :cl)) 22 | (in-package :ros.script.lem-ncurses-ccl.3724915314) 23 | 24 | (defun main (&rest argv) 25 | (apply #'lem:lem argv)) 26 | ;;; vim: set ft=lisp lisp: 27 | -------------------------------------------------------------------------------- /roswell/lem-ncurses.ros: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #|-*- mode:lisp -*-|# 3 | #| lem simple emacs clone. 4 | exec ros +Q -m lem-ncurses -L sbcl-bin -- $0 "$@" 5 | |# 6 | (progn 7 | (ros:ensure-asdf) 8 | (uiop:with-current-directory ((asdf:system-source-directory :lem)) 9 | (setf (uiop:getenv "SBCL_HOME") "") 10 | (uiop:run-program '("qlot" "install" "--no-deps") 11 | :output t 12 | :error-output t) 13 | #+quicklisp 14 | (setf ql:*quicklisp-home* 15 | (merge-pathnames #P".qlot/")) 16 | (load (merge-pathnames #P".qlot/setup.lisp"))) 17 | (unless (find-package :lem) 18 | (uiop:symbol-call :ql :quickload :lem-ncurses :silent t) 19 | (uiop:symbol-call :lem-core :load-site-init)) 20 | (when (find :roswell.dump.executable *features*) 21 | (mapc (lambda (x) 22 | (load x :verbose t)) 23 | (directory (merge-pathnames "scripts/build/*.lisp" 24 | (asdf/system:system-source-directory :lem)))))) 25 | 26 | (defpackage :ros.script.lem.3672618460 27 | (:use :cl)) 28 | (in-package :ros.script.lem.3672618460) 29 | 30 | (defun main (&rest argv) 31 | (apply #'lem:lem argv)) 32 | ;;; vim: set ft=lisp lisp: 33 | -------------------------------------------------------------------------------- /roswell/lem-sdl2.ros: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #|-*- mode:lisp -*-|# 3 | #| lem launcher for SDL2 frontend 4 | exec ros +Q -m lem-sdl2 -L sbcl-bin -- $0 "$@" 5 | |# 6 | (progn 7 | (ros:ensure-asdf) 8 | (uiop:with-current-directory ((asdf:system-source-directory :lem)) 9 | (setf (uiop:getenv "SBCL_HOME") "") 10 | (uiop:run-program '("qlot" "install" "--no-deps") 11 | :output t 12 | :error-output t) 13 | #+quicklisp 14 | (setf ql:*quicklisp-home* 15 | (merge-pathnames #P".qlot/")) 16 | (load (merge-pathnames #P".qlot/setup.lisp"))) 17 | (unless (find-package :lem) 18 | (uiop:symbol-call :ql :quickload :lem-sdl2 :silent t) 19 | (uiop:symbol-call :lem-core :load-site-init)) 20 | (when (find :roswell.dump.executable *features*) 21 | (mapc (lambda (x) 22 | (load x :verbose t)) 23 | (directory (merge-pathnames "scripts/build/*.lisp" 24 | (asdf/system:system-source-directory :lem)))))) 25 | 26 | (defpackage :ros.script.lem-sdl2.3891688398 27 | (:use :cl)) 28 | (in-package :ros.script.lem-sdl2.3891688398) 29 | 30 | (defun main (&rest argv) 31 | (apply #'lem:lem argv)) 32 | ;;; vim: set ft=lisp lisp: 33 | -------------------------------------------------------------------------------- /roswell/lem.ros: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #|-*- mode:lisp -*-|# 3 | #| 4 | exec ros -Q -- $0 "$@" 5 | |# 6 | (progn ;;init forms 7 | (ros:ensure-asdf) 8 | #+quicklisp(ql:quickload '() :silent t) 9 | ) 10 | 11 | (defpackage :ros.script.lem.3864804718 12 | (:use :cl)) 13 | (in-package :ros.script.lem.3864804718) 14 | 15 | (defvar *default-frontend* "ncurses") 16 | 17 | (defun main (&rest argv) 18 | (let ((cwd (uiop:getcwd)) 19 | (frontend (or (uiop:getenv "LEM_DEFAULT_FRONTEND") *default-frontend*))) 20 | (loop with flag = t 21 | do (cond ((find (first argv) '("--frontend" "-f") :test 'equal) 22 | (setf frontend (second argv) 23 | argv (cddr argv))) 24 | ((equal (first argv) "--") 25 | (setf argv (cdr argv) 26 | flag nil)) 27 | (t (setf flag nil))) 28 | while flag) 29 | (let* ((name (format nil "lem-~A~A" frontend (or #+win32 ".exe" ""))) 30 | (local (merge-pathnames name cwd)) 31 | (cmd (roswell.util:which name))) 32 | (cond 33 | ((uiop:file-exists-p local) 34 | (funcall 'roswell:exec (cons local argv))) 35 | (cmd 36 | (funcall 'roswell:exec (cons cmd argv))) 37 | (t 38 | (format t "unknown frontend: ~A~%" frontend) 39 | 1))))) 40 | ;;; vim: set ft=lisp lisp: 41 | -------------------------------------------------------------------------------- /screenshots/electron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/screenshots/electron.png -------------------------------------------------------------------------------- /screenshots/pdcurses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/screenshots/pdcurses.png -------------------------------------------------------------------------------- /screenshots/sdl2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/screenshots/sdl2.png -------------------------------------------------------------------------------- /screenshots/terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/screenshots/terminal.png -------------------------------------------------------------------------------- /scripts/build-ncurses.lisp: -------------------------------------------------------------------------------- 1 | (ql:quickload :lem-ncurses) 2 | 3 | (lem:init-at-build-time) 4 | 5 | (sb-ext:save-lisp-and-die "lem" 6 | :toplevel #'lem:main 7 | :executable t) 8 | -------------------------------------------------------------------------------- /scripts/build-sdl2-ncurses.lisp: -------------------------------------------------------------------------------- 1 | (ql:quickload :lem-sdl2) 2 | (ql:quickload :lem-ncurses) 3 | 4 | (lem:init-at-build-time) 5 | 6 | (sb-ext:save-lisp-and-die "lem" 7 | :toplevel #'lem:main 8 | :executable t) 9 | -------------------------------------------------------------------------------- /scripts/build-sdl2.lisp: -------------------------------------------------------------------------------- 1 | (ql:quickload :lem-sdl2) 2 | 3 | (lem:init-at-build-time) 4 | 5 | (sb-ext:save-lisp-and-die "lem" 6 | :toplevel #'lem:main 7 | :executable t) 8 | -------------------------------------------------------------------------------- /scripts/build-server.lisp: -------------------------------------------------------------------------------- 1 | (ql:quickload :lem-server) 2 | 3 | (lem:init-at-build-time) 4 | 5 | (sb-ext:save-lisp-and-die "lem-server" 6 | :toplevel #'lem-server:main 7 | :executable t) 8 | -------------------------------------------------------------------------------- /scripts/install/lem.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Lem 3 | Comment=Common Lisp editor/IDE with high expansibility 4 | Exec=/usr/local/bin/lem -i sdl2 %F 5 | MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;application/x-shellscript;text/x-c;text/x-c++; 6 | Icon=lem 7 | Terminal=false 8 | Type=Application 9 | Categories=Development;TextEditor; -------------------------------------------------------------------------------- /scripts/install/lem.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lem-project/lem/a951aedc72cd40fb8b0eada8923f088afb25caff/scripts/install/lem.ico -------------------------------------------------------------------------------- /scripts/launch-tests.lisp: -------------------------------------------------------------------------------- 1 | (ql:quickload :lem-tests) 2 | 3 | (rove:run :lem-tests) 4 | 5 | (quit) 6 | -------------------------------------------------------------------------------- /src/buffer-ext.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (define-editor-variable kill-buffer-hook '()) 4 | 5 | (defun strip-buffer-from-frame-windows (buffer frame) 6 | (dolist (window (get-buffer-windows buffer :frame frame :include-floating-windows t)) 7 | (with-current-window window 8 | (switch-to-buffer (or (get-previous-buffer buffer) 9 | (first (last (buffer-list)))))))) 10 | 11 | (defmethod delete-buffer-using-manager :before 12 | ((manager buffer-list-manager) 13 | buffer) 14 | (dolist (frame (all-frames)) 15 | (strip-buffer-from-frame-windows buffer frame)) 16 | (run-hooks (make-per-buffer-hook :var 'kill-buffer-hook :buffer buffer) buffer)) 17 | -------------------------------------------------------------------------------- /src/buffer/buffer-list-manager.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/buffer/buffer-list-manager 2 | (:use :cl) 3 | (:export 4 | :delete-buffer-using-manager 5 | :buffer-list-manager 6 | :with-current-buffers)) 7 | (in-package :lem/buffer/buffer-list-manager) 8 | 9 | (defgeneric delete-buffer-using-manager (buffer-list-manager buffer)) 10 | 11 | (defclass buffer-list-manager () 12 | ((buffers 13 | :initarg :buffers 14 | :initform '() 15 | :accessor buffer-list-manager-buffers))) 16 | 17 | (defvar *buffer-list-manager* (make-instance 'buffer-list-manager)) 18 | 19 | (defun buffer-list-manager () 20 | *buffer-list-manager*) 21 | 22 | (defun call-with-current-buffers (buffer-list function) 23 | (let ((buffers (buffer-list-manager-buffers (buffer-list-manager)))) 24 | (setf (buffer-list-manager-buffers (buffer-list-manager)) buffer-list) 25 | (unwind-protect (funcall function) 26 | (setf (buffer-list-manager-buffers (buffer-list-manager)) buffers)))) 27 | 28 | (defmacro with-current-buffers (buffer-list &body body) 29 | `(call-with-current-buffers ,buffer-list (lambda () ,@body))) 30 | -------------------------------------------------------------------------------- /src/buffer/errors.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/buffer/errors 2 | (:use :cl) 3 | (:export :editor-condition 4 | :directory-does-not-exist 5 | :directory-does-not-exist-directory 6 | :read-only-error 7 | :editor-error 8 | :scan-error 9 | :editor-interrupt)) 10 | (in-package :lem/buffer/errors) 11 | 12 | (define-condition editor-condition (simple-error) 13 | ()) 14 | 15 | (define-condition directory-does-not-exist (editor-condition) 16 | ((directory :initarg :directory 17 | :reader directory-does-not-exist-directory)) 18 | (:report (lambda (condition stream) 19 | (format stream "directory does not exist: ~A" 20 | (directory-does-not-exist-directory condition))))) 21 | 22 | (define-condition read-only-error (editor-condition) 23 | () 24 | (:report (lambda (condition stream) 25 | (declare (ignore condition)) 26 | (princ "Read Only" stream)))) 27 | 28 | (define-condition editor-error (editor-condition) 29 | ((message 30 | :initform nil 31 | :initarg :message)) 32 | (:report 33 | (lambda (condition stream) 34 | (with-slots (message) condition 35 | (when message 36 | (princ message stream)))))) 37 | 38 | (defun editor-error (message &rest args) 39 | (error 'editor-error :message (apply #'format nil message args))) 40 | 41 | (defun scan-error () 42 | (editor-error "Scan Error")) 43 | 44 | (define-condition editor-interrupt (simple-error) 45 | () 46 | (:report 47 | (lambda (condition stream) 48 | (declare (ignore condition)) 49 | (princ "Interrupt" stream)))) 50 | -------------------------------------------------------------------------------- /src/buffer/internal/editor-variables.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem/buffer/internal) 2 | 3 | (define-editor-variable tab-width +default-tab-size+) 4 | -------------------------------------------------------------------------------- /src/buffer/internal/mark.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem/buffer/internal) 2 | 3 | (defclass mark () 4 | ((point :initform nil 5 | :type (or null point) 6 | :accessor mark-point) 7 | (active :initform nil 8 | :type boolean 9 | :accessor mark-active-p))) 10 | 11 | (defmethod mark-cancel ((mark mark)) 12 | (setf (mark-active-p mark) nil)) 13 | 14 | (defmethod mark-set-point ((mark mark) point) 15 | (setf (mark-active-p mark) t) 16 | (if (mark-point mark) 17 | (move-point (mark-point mark) point) 18 | (setf (mark-point mark) 19 | (copy-point point :right-inserting))) 20 | point) 21 | -------------------------------------------------------------------------------- /src/buffer/interrupt.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/buffer/interrupt 2 | (:use :cl) 3 | (:export :without-interrupts 4 | :interrupt)) 5 | (in-package :lem/buffer/interrupt) 6 | 7 | (defvar *interrupts-enabled* t) 8 | (defvar *interrupted* nil) 9 | 10 | (defmacro %without-interrupts (&body body) 11 | `(#+sbcl sb-sys:without-interrupts 12 | #+ccl ccl:without-interrupts 13 | #-(or sbcl ccl) progn 14 | ,@body)) 15 | 16 | (defmacro without-interrupts (&body body) 17 | (let ((prev-enabled (gensym))) 18 | `(let ((,prev-enabled *interrupts-enabled*) 19 | (*interrupts-enabled* nil)) 20 | (prog1 (progn ,@body) 21 | (when (and *interrupted* ,prev-enabled) 22 | (%without-interrupts 23 | (setf *interrupted* nil) 24 | (error 'lem/buffer/errors:editor-interrupt))))))) 25 | 26 | ;; 別のスレッドから(bt2:interrupt-thread thread #'interrupt)で使う関数 27 | (defun interrupt (&optional force) 28 | (cond 29 | (force 30 | (error 'lem/buffer/errors:editor-interrupt)) 31 | (*interrupts-enabled* 32 | (error 'lem/buffer/errors:editor-interrupt)) 33 | (t 34 | (setf *interrupted* t)))) 35 | -------------------------------------------------------------------------------- /src/buffer/syntax-table.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/buffer/syntax-table 2 | (:use :cl) 3 | (:export :make-syntax-table 4 | :syntax-table-space-chars 5 | :syntax-table-symbol-chars 6 | :syntax-table-paren-pairs 7 | :syntax-table-string-quote-chars 8 | :syntax-table-escape-chars 9 | :syntax-table-fence-chars 10 | :syntax-table-expr-prefix-chars 11 | :syntax-table-expr-suffix-chars 12 | :syntax-table-expr-prefix-forward-function 13 | :syntax-table-expr-prefix-backward-function 14 | :syntax-table-line-comment-string 15 | :syntax-table-block-comment-pairs 16 | :syntax-table-block-string-pairs 17 | :syntax-table-parser 18 | :set-syntax-parser 19 | :fundamental-syntax-table)) 20 | (in-package :lem/buffer/syntax-table) 21 | 22 | (defstruct syntax-table 23 | (space-chars '(#\space #\tab #\newline)) 24 | (symbol-chars '(#\_)) 25 | (paren-pairs '((#\( . #\)) 26 | (#\[ . #\]) 27 | (#\{ . #\}))) 28 | (string-quote-chars '(#\")) 29 | (escape-chars '(#\\)) 30 | fence-chars 31 | expr-prefix-chars 32 | expr-suffix-chars 33 | expr-prefix-forward-function 34 | expr-prefix-backward-function 35 | line-comment-string 36 | block-comment-pairs 37 | block-string-pairs 38 | parser) 39 | 40 | (defun set-syntax-parser (syntax-table parser) 41 | (setf (syntax-table-parser syntax-table) parser)) 42 | 43 | (defparameter *fundamental-syntax-table* (make-syntax-table)) 44 | 45 | (defun fundamental-syntax-table () 46 | *fundamental-syntax-table*) 47 | -------------------------------------------------------------------------------- /src/clipboard.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defun wsl-p () 4 | "Return t when we are using WSL." 5 | (zerop (nth-value 2 (uiop:run-program '("which" "clip.exe") :ignore-error-status t)))) 6 | 7 | (defun sbcl-2.0.0-or-later-p () 8 | "Return t when we are using SBCL 2.0.0 or later." 9 | (and (string-equal "sbcl" (lisp-implementation-type)) 10 | (let ((version (mapcar #'parse-integer 11 | (uiop:split-string (lisp-implementation-version) 12 | :separator ".")))) 13 | (trivia:match version 14 | ((cons major _) 15 | (<= 2 major)))))) 16 | 17 | (defparameter *enable-clipboard-p* 18 | (ignore-errors 19 | #+darwin (sbcl-2.0.0-or-later-p) 20 | #-darwin (not (wsl-p)))) 21 | 22 | (defmacro with-enable-clipboard (value &body body) 23 | "Execute BODY with clipboard enabled/disabled. 24 | 25 | Argument VALUE is a boolean, and it will be set to enable/disable the clipboard." 26 | `(let ((*enable-clipboard-p* ,value)) 27 | ,@body)) 28 | 29 | (defun enable-clipboard () 30 | "Enable clipboard." 31 | (setf *enable-clipboard-p* t)) 32 | 33 | (defun disable-clipboard () 34 | "Disable clipboard." 35 | (setf *enable-clipboard-p* nil)) 36 | 37 | (defun enable-clipboard-p () 38 | "Return t if clipboard is enabled." 39 | *enable-clipboard-p*) 40 | 41 | (defun copy-to-clipboard (string) 42 | "Save STRING to clipboard, so it lives on top of the stack." 43 | (lem-if:clipboard-copy (implementation) string)) 44 | 45 | (defun get-clipboard-data () 46 | "Return the clipboard data." 47 | (lem-if:clipboard-paste (implementation))) 48 | -------------------------------------------------------------------------------- /src/command-advices.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defclass movable-advice () ()) 4 | (defclass jump-cursor-advice () ()) 5 | (defclass editable-advice () ()) 6 | 7 | ;;; multiple cursors 8 | (defun process-each-cursors (function) 9 | (let ((buffer (current-buffer))) 10 | (dolist (point (sort (copy-list (buffer-fake-cursors buffer)) #'point<)) 11 | (with-buffer-point (buffer point) 12 | (with-current-killring (fake-cursor-killring point) 13 | (handler-case 14 | (save-continue-flags 15 | (funcall function)) 16 | (move-cursor-error ()))))) 17 | (funcall function))) 18 | 19 | (defmacro do-each-cursors (() &body body) 20 | `(process-each-cursors (lambda () ,@body))) 21 | 22 | (defmethod execute :around (mode 23 | (command movable-advice) 24 | argument) 25 | (process-each-cursors #'call-next-method)) 26 | 27 | (defmethod execute :around (mode 28 | (command editable-advice) 29 | argument) 30 | (process-each-cursors #'call-next-method)) 31 | 32 | (defmethod execute :around (mode 33 | (command jump-cursor-advice) 34 | argument) 35 | (prog1 (call-next-method) 36 | (clear-cursors (current-buffer)))) 37 | -------------------------------------------------------------------------------- /src/commands/buffer.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-core/commands/buffer 2 | (:use :cl :lem-core) 3 | (:export :*read-only-function* 4 | :indent-current-buffer 5 | :toggle-read-only 6 | :rename-buffer 7 | :unmark-buffer) 8 | #+sbcl 9 | (:lock t)) 10 | (in-package :lem-core/commands/buffer) 11 | 12 | (defvar *read-only-function* nil) 13 | 14 | (define-key *global-keymap* "C-x C-q" 'toggle-read-only) 15 | (define-key *global-keymap* "M-~" 'unmark-buffer) 16 | 17 | (define-command indent-current-buffer () () 18 | "Indent the current buffer." 19 | (indent-buffer (current-buffer))) 20 | 21 | (define-command toggle-read-only () () 22 | "Toggle the buffer read-only." 23 | (setf (buffer-read-only-p (current-buffer)) 24 | (not (buffer-read-only-p (current-buffer)))) 25 | (when *read-only-function* 26 | (funcall *read-only-function* 27 | (buffer-read-only-p (current-buffer))))) 28 | 29 | (define-command rename-buffer (name) ((:string "Rename buffer: ")) 30 | "Rename the buffer." 31 | (buffer-rename (current-buffer) name)) 32 | 33 | (define-command unmark-buffer () () 34 | "Remove the mark where the buffer was changed." 35 | (buffer-unmark (current-buffer))) 36 | -------------------------------------------------------------------------------- /src/commands/font.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-core/commands/font 2 | (:use :cl :lem-core) 3 | (:export :font-size-increase 4 | :font-size-decrease) 5 | #+sbcl 6 | (:lock t)) 7 | (in-package :lem-core/commands/font) 8 | 9 | (define-key *global-keymap* "C-+" 'font-size-increase) 10 | (define-key *global-keymap* "C--" 'font-size-decrease) 11 | 12 | (define-command font-size-increase () () 13 | "Make the font larger (this currently only works with SDL2 frontend)" 14 | (lem-if:increase-font-size (implementation))) 15 | 16 | (define-command font-size-decrease () () 17 | "Make the font smaller (this currently only works with SDL2 frontend)" 18 | (lem-if:decrease-font-size (implementation))) 19 | 20 | (define-command font-size-set (size) ((:number "Size: ")) 21 | "Set the font size to an integer (this currently only works with SDL2 frontend)" 22 | (lem-if:set-font-size (implementation) size)) 23 | -------------------------------------------------------------------------------- /src/commands/frame.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-core/commands/frame 2 | (:use :cl :lem-core) 3 | (:export :toggle-frame-fullscreen) 4 | #+sbcl 5 | (:lock t)) 6 | (in-package :lem-core/commands/frame) 7 | 8 | (define-command toggle-frame-fullscreen () () 9 | "Toggles fullscreen." 10 | (setf (display-fullscreen-p) (not (display-fullscreen-p)))) 11 | 12 | (define-command maximize-frame () () 13 | "Maximize the frame." 14 | (lem-if:maximize-frame (implementation))) 15 | 16 | (define-command minimize-frame () () 17 | "Minimize the frame." 18 | (lem-if:minimize-frame (implementation))) 19 | -------------------------------------------------------------------------------- /src/commands/mark.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-core/commands/mark 2 | (:use :cl :lem-core) 3 | (:export :mark-set 4 | :exchange-point-mark 5 | :mark-set-whole-buffer) 6 | #+sbcl 7 | (:lock t)) 8 | (in-package :lem-core/commands/mark) 9 | 10 | (define-key *global-keymap* "C-@" 'mark-set) 11 | (define-key *global-keymap* "C-Space" 'mark-set) 12 | (define-key *global-keymap* "C-x C-x" 'exchange-point-mark) 13 | (define-key *global-keymap* "C-x h" 'mark-set-whole-buffer) 14 | 15 | (define-command mark-set () () 16 | "Sets a mark at the current cursor position." 17 | (run-hooks *set-location-hook* (current-point)) 18 | (set-cursor-mark (current-point) (current-point)) 19 | (message "Mark set")) 20 | 21 | (define-command exchange-point-mark () () 22 | "Exchange the current cursor position with the marked position." 23 | (check-marked) 24 | (alexandria:when-let ((mark (mark-point (cursor-mark (current-point))))) 25 | (with-point ((current (current-point))) 26 | (move-point (current-point) mark) 27 | (set-cursor-mark (current-point) current)))) 28 | 29 | (define-command (mark-set-whole-buffer (:advice-classes jump-cursor-advice)) () () 30 | "Select the whole buffer as a region." 31 | (buffer-end (current-point)) 32 | (set-current-mark (current-point)) 33 | (buffer-start (current-point)) 34 | (message "Mark set whole buffer")) 35 | 36 | (defmethod execute :around (mode 37 | (command mark-set) 38 | argument) 39 | (process-each-cursors #'call-next-method)) 40 | 41 | (defmethod execute :around (mode 42 | (command exchange-point-mark) 43 | argument) 44 | (process-each-cursors #'call-next-method)) 45 | -------------------------------------------------------------------------------- /src/commands/multiple-cursors.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-core/commands/multiple-cursors 2 | (:use :cl :lem-core) 3 | (:export :add-cursors-to-next-line) 4 | #+sbcl 5 | (:lock t)) 6 | (in-package :lem-core/commands/multiple-cursors) 7 | 8 | (define-key *global-keymap* "M-C" 'add-cursors-to-next-line) 9 | 10 | (define-command add-cursors-to-next-line () () 11 | "Duplicates the cursor under the currently existing cursors." 12 | (let ((cursors (buffer-cursors (current-buffer)))) 13 | (loop :for (cursor next-cursor) :on cursors 14 | :do (with-point ((p cursor)) 15 | (when (and (line-offset p 1 (point-charpos p)) 16 | (or (null next-cursor) 17 | (not (same-line-p p next-cursor)))) 18 | (make-fake-cursor p)))))) 19 | 20 | (defun clear-duplicate-cursors (buffer) 21 | (loop :for (cursor next-cursor) :on (buffer-cursors buffer) 22 | :when (and next-cursor (same-line-p cursor next-cursor)) 23 | :do (delete-fake-cursor 24 | (if (eq cursor (buffer-point buffer)) 25 | next-cursor 26 | cursor)))) 27 | 28 | (defun garbage-collection-cursors () 29 | (clear-duplicate-cursors (current-buffer))) 30 | 31 | (add-hook *post-command-hook* 'garbage-collection-cursors) 32 | 33 | (defun clear-cursors-when-aborted () 34 | (let ((string (merge-cursor-killrings (current-buffer)))) 35 | (clear-cursors (current-buffer)) 36 | (copy-to-clipboard-with-killring string))) 37 | 38 | (add-hook *editor-abort-hook* 'clear-cursors-when-aborted) 39 | -------------------------------------------------------------------------------- /src/common/character/icon.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/common/character/icon 2 | (:use :cl) 3 | (:export :register-icon 4 | :register-icon-ext 5 | :icon-code-p 6 | :icon-string 7 | :icon-string-by-ext 8 | :icon-value)) 9 | (in-package :lem/common/character/icon) 10 | 11 | (defvar *icon-name-table* (make-hash-table :test 'equal)) 12 | (defvar *icon-code-table* (make-hash-table :test 'eql)) 13 | (defvar *icon-ext-table* (make-hash-table :test 'equal)) 14 | 15 | (defstruct icon 16 | name 17 | code 18 | plist) 19 | 20 | (defun register-icon (name code &rest plist) 21 | (let ((icon (make-icon :name name :code code :plist plist))) 22 | (setf (gethash code *icon-code-table*) icon) 23 | (setf (gethash name *icon-name-table*) icon) 24 | icon)) 25 | 26 | (defun register-icon-ext (ext name) 27 | (setf (gethash ext *icon-ext-table*) name)) 28 | 29 | (defun icon-code-p (code) 30 | (not (null (gethash code *icon-code-table*)))) 31 | 32 | (defun icon-string (name) 33 | (let ((icon (gethash name *icon-name-table*))) 34 | (when icon 35 | (string (code-char (icon-code icon)))))) 36 | 37 | (defun icon-string-by-ext (ext) 38 | (let ((name (gethash ext *icon-ext-table*))) 39 | (icon-string name))) 40 | 41 | (defun icon-value (code key) 42 | (let ((icon (gethash code *icon-code-table*))) 43 | (when icon 44 | (getf (icon-plist icon) key)))) 45 | 46 | (register-icon "folder" #x1f4c1) 47 | (register-icon "lock" #x1F512) 48 | (register-icon "right-pointing-triangle" #x25B8) 49 | (register-icon "down-pointing-triangle" #x25BE) 50 | -------------------------------------------------------------------------------- /src/common/character/package.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem/common/character 2 | (:use-reexport :lem/common/character/eastasian) 3 | (:use-reexport :lem/common/character/icon) 4 | (:use-reexport :lem/common/character/string-width-utils)) 5 | -------------------------------------------------------------------------------- /src/common/hooks.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/common/hooks 2 | (:use :cl) 3 | (:export :run-hooks 4 | :add-hook 5 | :remove-hook)) 6 | (in-package :lem/common/hooks) 7 | 8 | (defgeneric run-hooks (hooks &rest args)) 9 | 10 | (defmethod run-hooks ((hooks list) &rest args) 11 | (dolist (hook hooks) 12 | (apply (car hook) args))) 13 | 14 | (defmacro add-hook (place callback &optional (weight 0)) 15 | (let ((_callback (gensym))) 16 | `(let ((,_callback ,callback)) 17 | (unless (member ,_callback ,place :key #'car) 18 | (setf ,place 19 | (merge 'list 20 | (list (cons ,_callback ,weight)) 21 | ,place 22 | #'> 23 | :key #'cdr)))))) 24 | 25 | (defmacro remove-hook (place callback) 26 | `(setf ,place (delete ,callback ,place :key #'car))) 27 | -------------------------------------------------------------------------------- /src/common/socket.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/common/socket 2 | (:use :cl) 3 | (:import-from :usocket) 4 | (:export :port-available-p 5 | :random-available-port) 6 | #+sbcl 7 | (:lock t)) 8 | (in-package :lem/common/socket) 9 | 10 | (defconstant +private-port-min+ 49152) 11 | (defconstant +private-port-max+ 65535) 12 | 13 | (defun port-available-p (port) 14 | (let (socket) 15 | (unwind-protect 16 | (handler-case (progn 17 | (setq socket (usocket:socket-listen "127.0.0.1" port :reuse-address nil)) 18 | port) 19 | (usocket:address-in-use-error () nil) 20 | (usocket:socket-error (e) 21 | (warn "USOCKET:SOCKET-ERROR: ~A" e) 22 | nil) 23 | #+sbcl 24 | (sb-bsd-sockets:socket-error (e) 25 | (warn "SB-BSD-SOCKETS:SOCKET-ERROR: ~A" e) 26 | nil)) 27 | (when socket 28 | (usocket:socket-close socket) 29 | port)))) 30 | 31 | (defun random-available-port (&rest deny-ports) 32 | (loop :for port := (random-port) 33 | :when (and (port-available-p port) 34 | (not (find port deny-ports :test #'equal))) 35 | :return port)) 36 | 37 | (defun random-port () 38 | (random-range +private-port-min+ +private-port-max+)) 39 | 40 | (defun random-range (min max &optional (state *random-state*)) 41 | (+ min (random (1+ (- max min)) state))) 42 | -------------------------------------------------------------------------------- /src/config.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defun lem-home () 4 | (let ((xdg-lem (uiop:xdg-config-home "lem/")) 5 | (dot-lem (merge-pathnames ".lem/" (user-homedir-pathname)))) 6 | (or (uiop:getenv "LEM_HOME") 7 | (and (probe-file dot-lem) dot-lem) 8 | xdg-lem))) 9 | 10 | (defun lem-logdir-pathname () 11 | (merge-pathnames "logs/" (lem-home))) 12 | 13 | (defun config-pathname () 14 | (merge-pathnames "config.lisp" (lem-home))) 15 | 16 | (defun ensure-config-pathname () 17 | (ensure-directories-exist (config-pathname))) 18 | 19 | (defun config-plist () 20 | (let ((pathname (ensure-config-pathname))) 21 | (if (uiop:file-exists-p pathname) 22 | (ignore-errors (uiop:read-file-form pathname)) 23 | '()))) 24 | 25 | (defun config (key &optional default) 26 | (let ((plist (config-plist))) 27 | (getf plist key default))) 28 | 29 | (defun (setf config) (value key &optional default) 30 | (declare (ignore default)) 31 | (let ((plist (config-plist))) 32 | (if (null plist) 33 | (setf plist (list key value)) 34 | (setf (getf plist key) value)) 35 | (with-open-file (out (ensure-config-pathname) 36 | :direction :output 37 | :if-exists :supersede 38 | :if-does-not-exist :create) 39 | (pprint plist out))) 40 | value) 41 | -------------------------------------------------------------------------------- /src/context-menu.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defun buffer-context-menu (buffer) 4 | (buffer-value buffer 'context-menu)) 5 | 6 | (defun (setf buffer-context-menu) (context-menu buffer) 7 | (setf (buffer-value buffer 'context-menu) context-menu)) 8 | -------------------------------------------------------------------------------- /src/display/char-type.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (deftype char-type () 4 | '(member :latin :cjk :braille :emoji :icon :control :zero-width)) 5 | 6 | (defun cjk-char-code-p (code) 7 | (or (<= #x4E00 code #x9FFF) 8 | (<= #x3040 code #x309F) 9 | (<= #x30A0 code #x30FF) 10 | (<= #xAC00 code #xD7A3))) 11 | 12 | (defun latin-char-code-p (code) 13 | (or (<= #x0000 code #x007F) 14 | (<= #x0080 code #x00FF) 15 | (<= #x0100 code #x017F) 16 | (<= #x0180 code #x024F))) 17 | 18 | (defun emoji-char-code-p (code) 19 | (or (<= #x1F300 code #x1F6FF) 20 | (<= #x1F900 code #x1F9FF) 21 | (<= #x1F600 code #x1F64F) 22 | (<= #x1F700 code #x1F77F))) 23 | 24 | (defun braille-char-code-p (code) 25 | (<= #x2800 code #x28ff)) 26 | 27 | (defun icon-char-code-p (code) 28 | (icon-value code :font)) 29 | 30 | (defun zero-width-char-code-p (code) 31 | (or (<= #x200B code #x200D) 32 | (<= #xFE00 code #xFE0F) 33 | (= code #xFEFF))) 34 | 35 | (defun char-type (char) 36 | (let ((code (char-code char))) 37 | (cond ((control-char char) 38 | :control) 39 | ((eql code #x1f4c1) 40 | :folder) 41 | ((<= code 128) 42 | :latin) 43 | ((icon-char-code-p code) 44 | :icon) 45 | ((braille-char-code-p code) 46 | :braille) 47 | ((cjk-char-code-p code) 48 | :cjk) 49 | ((latin-char-code-p code) 50 | :latin) 51 | ((emoji-char-code-p code) 52 | :emoji) 53 | ((icon-code-p code) 54 | :latin) 55 | ((zero-width-char-code-p code) 56 | :zero-width) 57 | (t 58 | :cjk)))) 59 | -------------------------------------------------------------------------------- /src/echo.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defparameter *message-timeout* 2) 4 | 5 | (defgeneric show-message (string &key timeout style &allow-other-keys)) 6 | (defgeneric clear-message ()) 7 | 8 | (defun log-message (string args) 9 | "Print a message. 10 | 11 | This function creates the `*Messages*` buffer before it writes. 12 | 13 | The first argument is a format control string, and the rest are data to be 14 | formatted under control of the string." 15 | (when string 16 | (let ((msg (apply #'format nil string args)) 17 | (buffer (make-buffer "*Messages*"))) 18 | (with-open-stream (stream (make-buffer-output-stream 19 | (buffer-end-point buffer))) 20 | (fresh-line stream) 21 | (princ msg stream))))) 22 | 23 | (defun message-without-log (string &rest args) 24 | "Print a message. 25 | 26 | This function does not write into the `*Messages*` buffer. 27 | 28 | The first argument is a format control string, and the rest are data to be 29 | formatted under control of the string." 30 | (if (null string) 31 | (clear-message) 32 | (show-message (apply #'format nil string args) 33 | :timeout *message-timeout*))) 34 | 35 | (defun message (string &rest args) 36 | "Print a message. 37 | 38 | The message goes into the `*Messages*` buffer and shows besides cursor. 39 | Return t if success. 40 | 41 | The first argument is a format control string, and the rest are data to be 42 | formatted under control of the string." 43 | (log-message string args) 44 | (apply #'message-without-log string args) 45 | (values)) 46 | 47 | (defun message-buffer (buffer) 48 | "Message BUFFER object." 49 | (show-message buffer)) 50 | -------------------------------------------------------------------------------- /src/errors.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defparameter *default-editor-abort-message* "Abort") 4 | 5 | (define-condition editor-abort (editor-condition) 6 | ((message 7 | :initarg :message 8 | :initform *default-editor-abort-message* 9 | :reader editor-abort-message)) 10 | (:report 11 | (lambda (condition stream) 12 | (when (editor-abort-message condition) 13 | (princ (editor-abort-message condition) stream))))) 14 | 15 | (define-condition exit-editor () 16 | ((report :initarg :report 17 | :reader exit-editor-report))) 18 | 19 | (define-condition undefined-key-error (editor-error) 20 | () 21 | (:report (lambda (c s) 22 | (declare (ignore c)) 23 | (format s 24 | "Key not found: ~A" 25 | (keyseq-to-string (last-read-key-sequence)))))) 26 | 27 | (define-condition move-cursor-error (editor-error) 28 | ((point :initarg :point 29 | :reader move-cursor-error-point))) 30 | 31 | (define-condition end-of-buffer (move-cursor-error) 32 | () 33 | (:default-initargs :message nil)) 34 | 35 | (define-condition beginning-of-buffer (move-cursor-error) 36 | () 37 | (:default-initargs :message nil)) 38 | -------------------------------------------------------------------------------- /src/event-queue.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defvar *editor-event-queue* (make-concurrent-queue)) 4 | 5 | (defun event-queue-length () 6 | (len *editor-event-queue*)) 7 | 8 | (defun send-event (obj) 9 | (enqueue *editor-event-queue* obj)) 10 | 11 | (defun send-abort-event (editor-thread force) 12 | (bt2:interrupt-thread editor-thread 13 | (lambda () 14 | (interrupt force)))) 15 | 16 | (defun receive-event (timeout) 17 | (loop 18 | (let ((e (dequeue *editor-event-queue* 19 | :timeout timeout 20 | :timeout-value :timeout))) 21 | (cond ((null e) 22 | (return nil)) 23 | ((eql e :timeout) 24 | (assert timeout) 25 | (return nil)) 26 | ((eql e :resize) 27 | (when (>= 1 (event-queue-length)) 28 | (update-on-display-resized))) 29 | ((or (functionp e) (symbolp e)) 30 | (funcall e)) 31 | (t 32 | (return e)))))) 33 | -------------------------------------------------------------------------------- /src/ext/directory-mode/attributes.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem/directory-mode/attributes 2 | (:use :cl :lem) 3 | (:export :current-directory-attribute 4 | :file-size-attribute 5 | :file-date-attribute 6 | :file-attribute 7 | :directory-attribute 8 | :link-attribute)) 9 | (in-package :lem/directory-mode/attributes) 10 | 11 | (eval-when (:compile-toplevel :load-toplevel :execute) 12 | (sb-ext:lock-package :lem/directory-mode/attributes)) 13 | 14 | (define-attribute current-directory-attribute 15 | (t :bold t)) 16 | 17 | (define-attribute file-size-attribute 18 | (t)) 19 | 20 | (define-attribute file-date-attribute 21 | (t)) 22 | 23 | (define-attribute file-attribute 24 | (t)) 25 | 26 | (define-attribute directory-attribute 27 | (t :foreground :base0D :bold t)) 28 | 29 | (define-attribute link-attribute 30 | (t :foreground :base0B :bold t)) 31 | -------------------------------------------------------------------------------- /src/ext/directory-mode/main.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem/directory-mode 2 | (:use :cl) 3 | (:use-reexport :lem/directory-mode/commands) 4 | (:use-reexport :lem/directory-mode/mode) 5 | (:import-from :lem/directory-mode/internal 6 | :*default-sort-method*) 7 | (:export :*default-sort-method* 8 | :*directory-mode-keymap*)) 9 | (in-package :lem/directory-mode) 10 | 11 | (eval-when (:compile-toplevel :load-toplevel :execute) 12 | (sb-ext:lock-package :lem/directory-mode)) 13 | 14 | (setf lem:*find-directory-function* 'lem/directory-mode/internal:directory-buffer) 15 | -------------------------------------------------------------------------------- /src/ext/directory-mode/mode.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem/directory-mode/mode 2 | (:use :cl :lem) 3 | (:export :directory-mode 4 | :*directory-mode-keymap*)) 5 | (in-package :lem/directory-mode/mode) 6 | 7 | (eval-when (:compile-toplevel :load-toplevel :execute) 8 | (sb-ext:lock-package :lem/directory-mode/mode)) 9 | 10 | (define-major-mode directory-mode () 11 | (:name "Directory" 12 | :keymap *directory-mode-keymap*) 13 | (setf (variable-value 'highlight-line :buffer (current-buffer)) nil)) 14 | -------------------------------------------------------------------------------- /src/ext/hover.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/hover 2 | (:use :cl :lem) 3 | (:export :show-hover)) 4 | (in-package :lem/hover) 5 | 6 | (defvar *hover-window* nil) 7 | 8 | (defun clear-hover-window () 9 | (delete-popup-message *hover-window*) 10 | (setf *hover-window* nil)) 11 | 12 | (defun clear-hover-window-if-unnecessary () 13 | (when (and (not (eq (current-window) *hover-window*)) 14 | (or (typep (this-command) 'movable-advice) 15 | (typep (this-command) 'editable-advice) 16 | (typep (this-command) 'keyboard-quit) 17 | (typep (this-command) 'escape))) 18 | (clear-hover-window))) 19 | 20 | (add-hook *pre-command-hook* 'clear-hover-window-if-unnecessary) 21 | 22 | (defun show-hover (buffer-or-string) 23 | (when *hover-window* 24 | (clear-hover-window)) 25 | (setf *hover-window* 26 | (display-popup-message buffer-or-string 27 | :timeout nil 28 | :style '(:gravity :cursor))) 29 | (setf (floating-window-focusable-p *hover-window*) t) 30 | (values)) 31 | -------------------------------------------------------------------------------- /src/ext/language-mode-tools.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/language-mode-tools 2 | (:use :cl :lem) 3 | (:export :make-tm-string-region 4 | :make-tm-line-comment-region 5 | :make-tm-block-comment-region) 6 | #+sbcl 7 | (:lock t)) 8 | (in-package :lem/language-mode-tools) 9 | 10 | (defun make-tm-string-region (sepalator &key (name 'syntax-string-attribute) 11 | (patterns (make-tm-patterns (make-tm-match "\\\\.")))) 12 | (make-tm-region `(:sequence ,sepalator) 13 | `(:sequence ,sepalator) 14 | :name name 15 | :patterns patterns)) 16 | 17 | (defun make-tm-line-comment-region (start) 18 | (make-tm-region start "$" :name 'syntax-comment-attribute)) 19 | 20 | (defun make-tm-block-comment-region (start end) 21 | (make-tm-region `(:sequence ,start) 22 | `(:sequence ,end) 23 | :name 'syntax-comment-attribute)) 24 | -------------------------------------------------------------------------------- /src/ext/read-only-sources.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem/read-only-sources 2 | (:use :cl :lem) 3 | (:export :read-only-sources 4 | :define-read-only-source)) 5 | (in-package :lem/read-only-sources) 6 | 7 | (define-editor-variable read-only-sources t) 8 | 9 | (defvar *patterns* (make-hash-table :test 'equal)) 10 | 11 | (defun register-pattern (name function) 12 | (setf (gethash name *patterns*) function)) 13 | 14 | (defmacro define-read-only-source (name (directory) &body body) 15 | `(register-pattern ',name (lambda (,directory) ,@body))) 16 | 17 | (defun read-only-source-p (directory) 18 | (maphash (lambda (name pattern) 19 | (declare (ignore name)) 20 | (when (funcall pattern directory) 21 | (return-from read-only-source-p t))) 22 | *patterns*)) 23 | 24 | (defun on-switch-to-buffer (buffer) 25 | (when (and (variable-value 'read-only-sources :default buffer) 26 | (read-only-source-p (buffer-directory buffer))) 27 | (setf (buffer-read-only-p buffer) t))) 28 | 29 | (add-hook *switch-to-buffer-hook* 'on-switch-to-buffer) 30 | -------------------------------------------------------------------------------- /src/ext/thingatp.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/thingatp 2 | (:use :cl :lem) 3 | (:export 4 | :urlp 5 | :url 6 | :pathp 7 | :path)) 8 | (in-package :lem/thingatp) 9 | 10 | (eval-when (:compile-toplevel :load-toplevel :execute) 11 | ;; URL 12 | (defun urlp (thing) 13 | (and 14 | (stringp thing) 15 | (numberp 16 | (ppcre:scan 17 | "(https://www\\.|http://www\\.|https://|http://|file://)[a-zA-Z0-9]{2,}(\\.[a-zA-Z0-9]{2,})?(\\.[a-zA-Z0-9]{2,})?" thing)))) 18 | 19 | (deftype url () 20 | `(satisfies urlp)) 21 | 22 | ;; PATH 23 | (defun pathp (thing) 24 | (and (ppcre:scan "^(.*)\/([^\/]*)$" thing) 25 | (or (uiop:directory-exists-p thing) 26 | (uiop:file-exists-p thing)))) 27 | 28 | (deftype path () 29 | `(satisfies pathp))) 30 | 31 | (define-command open-at-point () () 32 | (let ((thing (symbol-string-at-point (lem:current-point)))) 33 | (typecase thing 34 | (url (open-external-file thing)) 35 | (path 36 | (lem:find-file (pathname thing))) 37 | (t 38 | (lem/language-mode:find-definitions))))) 39 | -------------------------------------------------------------------------------- /src/external-packages.lisp: -------------------------------------------------------------------------------- 1 | (uiop:define-package :lem 2 | (:use :cl) 3 | (:use-reexport :lem-core) 4 | (:use-reexport :lem-core/commands/multiple-cursors) 5 | (:use-reexport :lem-core/commands/move) 6 | (:use-reexport :lem-core/commands/edit) 7 | (:use-reexport :lem-core/commands/mark) 8 | (:use-reexport :lem-core/commands/word) 9 | (:use-reexport :lem-core/commands/s-expression) 10 | (:use-reexport :lem-core/commands/file) 11 | (:use-reexport :lem-core/commands/window) 12 | (:use-reexport :lem-core/commands/buffer) 13 | (:use-reexport :lem-core/commands/process) 14 | (:use-reexport :lem-core/commands/help) 15 | (:use-reexport :lem-core/commands/font) 16 | (:use-reexport :lem-core/commands/other) 17 | (:use-reexport :lem-core/commands/frame)) 18 | #+sbcl 19 | (sb-ext:lock-package :lem) 20 | 21 | (defpackage :lem-user 22 | (:use :cl :lem)) 23 | -------------------------------------------------------------------------------- /src/fundamental-mode.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (define-major-mode lem/buffer/fundamental-mode:fundamental-mode nil 4 | (:name "Fundamental")) 5 | 6 | (defvar *global-keymap* (make-keymap :name '*global-keymap*)) 7 | 8 | (define-global-mode emacs-mode () 9 | (:name "emacs" 10 | :keymap *global-keymap*)) 11 | -------------------------------------------------------------------------------- /src/highlight-line.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (define-editor-variable highlight-line nil) 4 | (define-editor-variable highlight-line-color nil) 5 | 6 | (defun highlight-line-color () 7 | (alexandria:if-let ((color (variable-value 'highlight-line-color))) 8 | color 9 | (guess-highlight-line-color))) 10 | 11 | (defun guess-highlight-line-color () 12 | (when (background-color) 13 | (let ((color (parse-color (background-color)))) 14 | (multiple-value-bind (h s v) 15 | (rgb-to-hsv (color-red color) 16 | (color-green color) 17 | (color-blue color)) 18 | (multiple-value-bind (r g b) 19 | (hsv-to-rgb h 20 | s 21 | (max 0 (- v 2))) 22 | (color-to-hex-string (make-color r g b))))))) 23 | -------------------------------------------------------------------------------- /src/html-buffer.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defclass html-buffer (text-buffer) 4 | ((html :initarg :html 5 | :reader html-buffer-html) 6 | (updated :initform nil 7 | :reader html-buffer-updated-p))) 8 | 9 | (defmethod (setf html-buffer-html) (html (buffer html-buffer)) 10 | (setf (slot-value buffer 'updated) t) 11 | (setf (slot-value buffer 'html) html)) 12 | 13 | (defmethod invalidate-html-buffer-updated ((buffer html-buffer)) 14 | (setf (slot-value buffer 'updated) nil)) 15 | 16 | (defun make-html-buffer (buffer-name html) 17 | (let ((buffer (make-buffer buffer-name))) 18 | (change-class buffer 'html-buffer :html html) 19 | buffer)) 20 | 21 | (defun js-eval (window code &key (wait nil)) 22 | (lem-if:js-eval (implementation) 23 | (window-view window) 24 | code 25 | :wait wait)) 26 | -------------------------------------------------------------------------------- /src/killring.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defvar *killring* (make-killring 10)) 4 | 5 | (defun current-killring () 6 | *killring*) 7 | 8 | (defmacro with-current-killring (killring &body body) 9 | `(let ((*killring* ,killring)) 10 | ,@body)) 11 | 12 | (defmacro with-disable-killring (() &body body) 13 | `(let ((*killring* (make-nop-killring))) 14 | ,@body)) 15 | 16 | (defun copy-to-clipboard-with-killring (string) 17 | (push-killring-item (current-killring) string) 18 | (when (enable-clipboard-p) 19 | (copy-to-clipboard (peek-killring-item (current-killring) 0)))) 20 | 21 | (defun yank-from-clipboard-or-killring () 22 | (multiple-value-bind (str options) (peek-killring-item (current-killring) 0) 23 | (or (and (enable-clipboard-p) (get-clipboard-data)) 24 | (values str options)))) 25 | -------------------------------------------------------------------------------- /src/region.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defgeneric check-marked-using-global-mode (global-mode buffer)) 4 | (defgeneric region-beginning-using-global-mode (global-mode &optional buffer)) 5 | (defgeneric region-end-using-global-mode (global-mode &optional buffer)) 6 | (defgeneric set-region-point-using-global-mode (global-mode start end)) 7 | 8 | (defmethod region-beginning-using-global-mode ((global-mode emacs-mode) 9 | &optional (buffer (current-buffer))) 10 | (region-beginning buffer)) 11 | 12 | (defmethod region-end-using-global-mode ((global-mode emacs-mode) 13 | &optional (buffer (current-buffer))) 14 | (region-end buffer)) 15 | 16 | (defmethod set-region-point-using-global-mode ((global-mode emacs-mode) (start point) (end point)) 17 | (declare (ignore global-mode)) 18 | (cond 19 | ((buffer-mark-p (current-buffer)) 20 | (move-point start (cursor-region-beginning (current-point))) 21 | (move-point end (cursor-region-end (current-point)))) 22 | (t 23 | (line-start start) 24 | (line-end end)))) 25 | 26 | (defmethod check-marked-using-global-mode ((global-mode emacs-mode) buffer) 27 | (unless (buffer-mark buffer) 28 | (editor-error "Not mark in this buffer"))) 29 | 30 | (defun check-marked () 31 | (check-marked-using-global-mode (current-global-mode) (current-buffer))) 32 | -------------------------------------------------------------------------------- /src/save-excursion.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defun invoke-save-excursion (function) 4 | (let ((point (copy-point (current-point) :right-inserting)) 5 | (mark (when (buffer-mark-p (current-buffer)) 6 | (copy-point (buffer-mark (current-buffer)) 7 | :right-inserting)))) 8 | (unwind-protect (funcall function) 9 | (setf (current-buffer) (point-buffer point)) 10 | (move-point (current-point) point) 11 | (delete-point point) 12 | (when mark 13 | (set-current-mark mark) 14 | (delete-point mark))))) 15 | 16 | (defmacro save-excursion (&body body) 17 | "Saves the current `point` and `mark`, restores them after evaluation of `body` and returns the result of `body`." 18 | `(invoke-save-excursion (lambda () ,@body))) 19 | -------------------------------------------------------------------------------- /src/system-utils.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defun maybe-load-systems (systems &key (silent t) verbose error-on-failure-p) 4 | "Load system SYSTEMS, potentially downloading them from an external 5 | repository. SYSTEMS may be a single system or a list of 6 | systems. Loader behavior is modified by VERBOSE and SILENT." 7 | (unless (listp systems) 8 | (setf systems (list systems))) 9 | (handler-bind ((error (lambda (e) 10 | (declare (ignore e)) 11 | (unless error-on-failure-p 12 | (return-from maybe-load-systems nil))))) 13 | (flet ((try-load-system (system) 14 | (or 15 | (when (find-package '#:OCICL-RUNTIME) 16 | (progv (list (find-symbol "*DOWNLOAD*" '#:OCICL-RUNTIME) 17 | (find-symbol "*VERBOSE*" '#:OCICL-RUNTIME)) 18 | (list t (or verbose (not silent))) 19 | (funcall (find-symbol "LOAD-SYSTEM" '#:ASDF) system))) 20 | (when (find-package '#:QUICKLISP) 21 | (funcall (find-symbol "QUICKLOAD" '#:QUICKLISP) 22 | system :verbose verbose :silent silent)) 23 | (when (find-package '#:ASDF) 24 | (funcall (find-symbol "LOAD-SYSTEM" '#:ASDF) system)) 25 | (error "Unable to find any system-loading mechanism.")))) 26 | (mapcar #'try-load-system systems)))) 27 | -------------------------------------------------------------------------------- /src/system.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defparameter *deployed* nil) 4 | 5 | (defun lem-relative-pathname (pathname) 6 | (when *deployed* 7 | (truename (merge-pathnames pathname 8 | #+sbcl 9 | (uiop:pathname-directory-pathname (first sb-ext:*posix-argv*)) 10 | #-sbcl 11 | (uiop:pathname-directory-pathname (uiop/os:getcwd)))))) 12 | 13 | (defun get-pid () 14 | #+sbcl 15 | (sb-posix:getpid) 16 | #+ccl 17 | (ccl::getpid) 18 | #+lispworks 19 | (progn 20 | #+win32 (win32:get-current-process-id) 21 | #-win32 (system::getpid))) 22 | 23 | (defun exist-program-p (program) 24 | (let ((status 25 | (nth-value 2 26 | (uiop:run-program (list "which" program) 27 | :ignore-error-status t)))) 28 | (= status 0))) 29 | 30 | (defun open-external-file (pathname) 31 | #+linux 32 | (uiop:launch-program (list "xdg-open" (namestring pathname))) 33 | #+darwin 34 | (uiop:launch-program (list "open" (namestring pathname))) 35 | #+windows 36 | (uiop:launch-program (list "explorer" (namestring pathname)) :ignore-error-status t)) 37 | -------------------------------------------------------------------------------- /src/version.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defun get-git-hash () 4 | "Return lem's git hash." 5 | (let ((path (asdf:system-relative-pathname :lem ".git/"))) 6 | (when (uiop:directory-exists-p path) 7 | (uiop:with-current-directory (path) 8 | (string-trim 9 | (list #\Newline #\Space) 10 | #+sbcl 11 | (with-output-to-string (stream) 12 | (uiop:run-program "git rev-parse --short HEAD" 13 | :output stream)) 14 | #-sbcl 15 | "" 16 | ))))) 17 | 18 | (defvar *git-revision* (get-git-hash) 19 | "Stores lem's git revision; this is treated as a cache.") 20 | 21 | (defun lem-git-revision () 22 | "Return lem's git revision in string." 23 | *git-revision*) 24 | 25 | (defun get-version-string () 26 | "Return the version number of this version of Lem." 27 | (format nil "lem ~A~@[-~A~] (~A-~A)" 28 | (asdf:component-version (asdf:find-system :lem)) 29 | *git-revision* 30 | (machine-type) 31 | (machine-instance))) 32 | -------------------------------------------------------------------------------- /src/window/header-window.lisp: -------------------------------------------------------------------------------- 1 | (in-package :lem-core) 2 | 3 | (defclass header-window (window) ()) 4 | 5 | (defmethod initialize-instance ((window header-window) &key &allow-other-keys) 6 | (with-slots (x y width height) window 7 | (setf x 0) 8 | (setf y (length (frame-header-windows (current-frame)))) 9 | (setf width (display-width)) 10 | (setf height 1)) 11 | (add-header-window (current-frame) window) 12 | (notify-header-window-modified (current-frame)) 13 | (call-next-method)) 14 | 15 | (defmethod %delete-window ((window header-window)) 16 | (remove-header-window (current-frame) window) 17 | (notify-header-window-modified (current-frame))) 18 | -------------------------------------------------------------------------------- /tests/completion.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-tests/completion 2 | (:use :cl 3 | :rove)) 4 | (in-package :lem-tests/completion) 5 | 6 | (deftest test-completion () 7 | (let ((items '("apple" "banana" "orange" "pineapple"))) 8 | (ok (equal '("apple" "banana" "orange" "pineapple") (lem:completion "a" items))) 9 | (ok (equal '("apple" "pineapple") (lem:completion "app" items))) 10 | (ok (equal '() (lem:completion "xyz" items))) 11 | (ok (equal '() (lem:completion "APP" items))) 12 | (ok (equal '("apple" "pineapple") (lem:completion "APP" items :key #'string-upcase))) 13 | (ok (equal '("foo-bar-baz" "foo-bar-y") 14 | (lem:completion "foo-bar" '("foo-bar-baz" "foo-bar-y" "x-foo-bar-y") 15 | :separator "-"))))) 16 | -------------------------------------------------------------------------------- /tests/e2e/vi-mode.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-tests/vi-mode 2 | (:use :cl 3 | :lem 4 | :testif) 5 | (:import-from :lem-fake-interface 6 | :fake-interface)) 7 | (in-package :lem-tests/vi-mode) 8 | 9 | ;;; このテストは不十分で動作も不安定なので、まだ動かさない 10 | 11 | (test vi-mode 12 | (lem) 13 | (sleep 0.1) 14 | (lem-vi-mode:vi-mode) 15 | (test "enable hook" 16 | (test "initialize-vi-modeline" 17 | (ok (and (lem-vi-mode/core::vi-modeline-element-p 18 | lem-vi-mode/core::*modeline-element*))) 19 | (ok (find-if (lambda (element) 20 | (and (lem-vi-mode/core::vi-modeline-element-p element) 21 | (equal "[COMMAND]" (lem-vi-mode/core::element-name element)))) 22 | lem-core::*modeline-status-list*))) 23 | (test "(change-state 'normal)" 24 | (ok (eq lem-vi-mode/core::*current-state* 'lem-vi-mode::command)) 25 | 26 | (ok (eq (mode-keymap (get 'lem-vi-mode:vi-mode 'lem-core::global-mode)) 27 | (lem-vi-mode/core::vi-state-keymap (lem-vi-mode/core::ensure-state 'lem-vi-mode::command)))) 28 | (ok (equal "[COMMAND]" (lem-vi-mode/core::element-name lem-vi-mode/core::*modeline-element*))) 29 | (ok (string= (if (eq :dark (lem-core::display-background-mode)) 30 | "white" 31 | "dark") 32 | (attribute-background (ensure-attribute 'cursor nil))))))) 33 | -------------------------------------------------------------------------------- /tests/file.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/tests/file 2 | (:use :cl :rove)) 3 | (in-package :lem/tests/file) 4 | 5 | (deftest get-file-mode 6 | (ok (equal 'lem-posix-shell-mode:posix-shell-mode 7 | (lem:get-file-mode ".bashrc"))) 8 | (ok (equal 'lem-posix-shell-mode:posix-shell-mode 9 | (lem:get-file-mode "foo.bashrc"))) 10 | (ok (equal 'lem-lisp-mode:lisp-mode 11 | (lem:get-file-mode "foo.lisp"))) 12 | (ok (null (lem:get-file-mode "foo.lisp.bak")))) 13 | -------------------------------------------------------------------------------- /tests/interp.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem/tests/interp 2 | (:use :cl :rove)) 3 | (in-package :lem/tests/interp) 4 | 5 | (defvar *result*) 6 | 7 | (lem:define-command $test-command-flag () () 8 | (let ((value (lem:continue-flag :test-command-flag))) 9 | (alexandria:nconcf *result* (list value)))) 10 | 11 | (defun execute-testing-command (n command-name &optional argument) 12 | (lem:do-command-loop () 13 | (lem:call-command command-name argument) 14 | (unless (plusp (decf n)) (return)))) 15 | 16 | (deftest Execute-the-same-command-consecutively 17 | (lem-fake-interface:with-fake-interface () 18 | (lem:with-current-buffers () 19 | (let ((*result* '())) 20 | (execute-testing-command 3 '$test-command-flag) 21 | (ok (equal '(nil t t) *result*)))))) 22 | -------------------------------------------------------------------------------- /tests/killring.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-tests/killring 2 | (:use :cl 3 | :rove 4 | :lem/common/killring 5 | :lem)) 6 | (in-package :lem-tests/killring) 7 | 8 | (deftest external-option 9 | (lem-fake-interface:with-fake-interface () 10 | (let ((killring (make-killring 2))) 11 | (with-killring-context (:appending t :before-inserting t) 12 | (push-killring-item killring "baz" :options :test)) 13 | 14 | ;; clipboard disabled 15 | (let ((lem-core::*enable-clipboard-p* nil) 16 | (lem-core::*killring* killring)) 17 | (ok (equal '("baz" (:test)) 18 | (multiple-value-list (yank-from-clipboard-or-killring))))) 19 | 20 | ;; clipboard enabled 21 | (let ((lem-core::*enable-clipboard-p* t) 22 | (lem-core::*killring* killring) 23 | (expected-result "In LEM we trust.")) 24 | (copy-to-clipboard-with-killring expected-result) 25 | (ok (equal expected-result 26 | (yank-from-clipboard-or-killring))))))) 27 | -------------------------------------------------------------------------------- /tests/language-server/micros-tests.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-language-server/micros-tests 2 | (:use :cl 3 | :rove 4 | :micros/lsp-api)) 5 | (in-package :lem-language-server/micros-tests) 6 | 7 | (defmacro with-micros-syntax (() &body body) 8 | `(let ((micros::*buffer-package* (find-package "CL-USER")) 9 | (micros::*buffer-readtable* *readtable*)) 10 | ,@body)) 11 | 12 | (deftest eval-tests 13 | (testing "return evaluated value" 14 | (with-micros-syntax () 15 | (let ((result (eval-for-language-server "(cons 1 2)"))) 16 | (ok (equal "(1 . 2)" (eval-result-value result))) 17 | (ok (null (eval-result-error result)))))) 18 | (testing "reader error" 19 | (with-micros-syntax () 20 | (let ((result (eval-for-language-server "(cons 1"))) 21 | (ok (null (eval-result-value result))) 22 | (ok (stringp (eval-result-error result))))))) 23 | 24 | (defun call-with-micros-connection (function) 25 | (let ((connection (micros/client:start-server-and-connect nil))) 26 | (unwind-protect (funcall function connection) 27 | (micros/client:stop-server connection)))) 28 | 29 | (defmacro with-micros-connection ((connection) &body body) 30 | `(call-with-micros-connection (lambda (,connection) ,@body))) 31 | 32 | (deftest simple-eval-test 33 | (with-micros-connection (connection) 34 | (let ((result 35 | (micros/client:remote-eval-sync connection 36 | `(micros:interactive-eval "(cons 1 2)")))) 37 | (ok (equal "=> (1 . 2)" result))))) 38 | -------------------------------------------------------------------------------- /tests/language-server/utils.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-tests/language-server/utils 2 | (:use :cl 3 | :lem-language-server) 4 | (:export :lines)) 5 | (in-package :lem-tests/language-server/utils) 6 | 7 | (defun lines (&rest strings) 8 | (format nil "~{~A~%~}" strings)) 9 | -------------------------------------------------------------------------------- /tests/prompt.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-tests/prompt 2 | (:use :cl :rove) 3 | (:import-from :lem-fake-interface 4 | :fake-interface 5 | :with-fake-interface)) 6 | (in-package :lem-tests/prompt) 7 | 8 | (deftest prompt-for-character 9 | (with-fake-interface () 10 | (lem:unread-key (lem:make-key :sym "a")) 11 | (ok (equal #\a 12 | (lem:prompt-for-character 13 | "test: " 14 | :gravity (make-instance 'lem/popup-window::gravity-cursor)))))) 15 | -------------------------------------------------------------------------------- /tests/sample-code/LemScalaIndent.scala: -------------------------------------------------------------------------------- 1 | object LemScalaIndent { 2 | def main(args: Array[String]): Unit = { 3 | for (i <- 0 until 100) { 4 | Option(i) 5 | .map(_ + 1) 6 | .map(_ % 2) 7 | 8 | val oneTwo: String = { 9 | val one = "one" 10 | val two = "two" 11 | s"$one$two" 12 | } 13 | 14 | trait Human[T] { 15 | val age: Int 16 | } 17 | 18 | trait Greeter { 19 | def sayHello: Unit 20 | } 21 | 22 | case class Person( 23 | val name: String, 24 | surname: String, 25 | override val age: Int 26 | ) extends Human[Person] 27 | with Greeter { 28 | override def sayHello: Unit = println(s"Hello, I'm $name! Nice to meet you") 29 | } 30 | 31 | val person = Person( 32 | name = "vasya", 33 | surname = "pupkin", 34 | age = 24 35 | ) 36 | 37 | person match { 38 | case Person(name, surname, age) => 39 | println(s"Person name: $name surname: $surname") 40 | case _ => 41 | throw new RuntimeException("Unrecognizable person") 42 | } 43 | 44 | if (person.name == "vasya") { 45 | println("Vasya is hear") 46 | } else { 47 | println("Vasya is lost") 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/sample-code/syntax-sample.lisp: -------------------------------------------------------------------------------- 1 | (defun foo () 2 | ;; abc " xyz 3 | bar) 4 | -------------------------------------------------------------------------------- /tests/sample-code/text.txt: -------------------------------------------------------------------------------- 1 | hello world 2 | -------------------------------------------------------------------------------- /tests/scala-mode.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-tests/scala-mode 2 | (:use :cl 3 | :rove 4 | :lem-tests/utilities)) 5 | (in-package :lem-tests/scala-mode) 6 | 7 | (deftest scala-indent-region 8 | (with-testing-buffer (buffer (lem:find-file-buffer (sample-file "LemScalaIndent.scala"))) 9 | (testing "Test indent region" 10 | (let ((before (lem:buffer-text buffer)) 11 | (after) 12 | (is-correct)) 13 | (lem:indent-current-buffer) 14 | (setq after (lem:buffer-text buffer)) 15 | (setq is-correct (string= before after)) 16 | (ok is-correct 17 | (if is-correct 18 | "Indent is correct" 19 | (diff-text before after))))))) 20 | -------------------------------------------------------------------------------- /tests/self-insert-command.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-tests/self-insert-command 2 | (:use :cl 3 | :lem 4 | :rove) 5 | (:import-from :lem-fake-interface 6 | :with-fake-interface)) 7 | (in-package :lem-tests/self-insert-command) 8 | 9 | (defun execute-self-insert (&rest key-seq) 10 | (erase-buffer (current-buffer)) 11 | (execute-key-sequence key-seq) 12 | (buffer-text (current-buffer))) 13 | 14 | (deftest self-insert-command 15 | (with-fake-interface () 16 | (ok "a" (execute-self-insert (make-key :sym "a"))) 17 | (ok "aaaa" (execute-self-insert (make-key :ctrl t :sym "u") (make-key :sym "a"))) 18 | (handler-case 19 | (progn 20 | (execute-key-sequence (list (make-key :super t :meta t :hyper t :sym "a"))) 21 | (fail "unreachable")) 22 | (editor-error (e) 23 | (ok (search "Key not found: " (princ-to-string e))))))) 24 | -------------------------------------------------------------------------------- /tests/thingatp.lisp: -------------------------------------------------------------------------------- 1 | (defpackage :lem-tests/thingatp 2 | (:use :cl :rove :lem/thingatp :lem)) 3 | 4 | 5 | (in-package :lem-tests/thingatp) 6 | 7 | (deftest url-type 8 | (let ((url-list-correct 9 | '("https://mypage.com/directory" 10 | "https://mypage.com/directory.txt" 11 | "https://mypage.com/directory.php" 12 | "https://mypage.com/my/dire/c/tory" 13 | "https://mypage.com/my/dire/c/tory.txt" 14 | 15 | "file://mypage/myfile.htm" 16 | )) 17 | (url-list-wrong 18 | '("not an url" 19 | "3" 20 | "this is a number" 21 | "htttttttp hey" 22 | "http:_+____" 23 | "none"))) 24 | (loop :for correct :in url-list-correct 25 | :for wrong :in url-list-wrong 26 | :do (progn 27 | (ok (typep correct 'url) ) 28 | (ok (not (typep wrong 'url))))))) 29 | 30 | (deftest path-type 31 | (let ((url-list-correct 32 | '("/usr/bin/" 33 | "/boot/initrd.img" 34 | "/" 35 | "/usr" 36 | "/usr/sbin/mkfs" 37 | )) 38 | (url-list-wrong 39 | '("not an url" 40 | "3" 41 | "___ 23 path_" 42 | "/ / / / / hey" 43 | "none"))) 44 | (loop :for correct :in url-list-correct 45 | :for wrong :in url-list-wrong 46 | :do (progn 47 | (ok (typep correct 'path) ) 48 | (ok (not (typep wrong 'path))))))) 49 | --------------------------------------------------------------------------------