{"id":13495157,"url":"https://github.com/elbywan/crystalline","last_synced_at":"2025-05-15T06:07:37.616Z","repository":{"id":40382910,"uuid":"294644080","full_name":"elbywan/crystalline","owner":"elbywan","description":"A Language Server Protocol implementation for Crystal. 🔮","archived":false,"fork":false,"pushed_at":"2025-04-30T16:20:35.000Z","size":10244,"stargazers_count":476,"open_issues_count":20,"forks_count":25,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-04-30T17:35:15.318Z","etag":null,"topics":["crystal","lsp","lsp-server","vscode-language"],"latest_commit_sha":null,"homepage":"","language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elbywan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"elbywan","custom":["https://www.paypal.me/elbywan"]}},"created_at":"2020-09-11T08:54:44.000Z","updated_at":"2025-04-30T16:20:39.000Z","dependencies_parsed_at":"2024-02-03T08:42:02.185Z","dependency_job_id":"185b70cc-9eb6-40b3-9ae4-af658c9f9e00","html_url":"https://github.com/elbywan/crystalline","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fcrystalline","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fcrystalline/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fcrystalline/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fcrystalline/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elbywan","download_url":"https://codeload.github.com/elbywan/crystalline/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254283340,"owners_count":22045140,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crystal","lsp","lsp-server","vscode-language"],"created_at":"2024-07-31T19:01:31.773Z","updated_at":"2025-05-15T06:07:37.609Z","avatar_url":"https://github.com/elbywan.png","language":"Crystal","funding_links":["https://github.com/sponsors/elbywan","https://www.paypal.me/elbywan"],"categories":["Crystal","LSP Language Server Protocol Implementations"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\t\u003cimg src=\"assets/icon.svg\" width=\"128\" height=\"128\" /\u003e\n\t\u003ch1\u003ecrystalline\u003c/h1\u003e\n  \u003ch3\u003eA Language Server for Crystal.\u003c/h3\u003e\n  \u003ca href=\"https://github.com/elbywan/crystalline/actions?query=branch%3Amaster+workflow%3ABuild\"\u003e\u003cimg alt=\"Build Status\" src=\"https://github.com/elbywan/crystalline/workflows/Build/badge.svg?branch=master\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/elbywan/crystalline/tags\"\u003e\u003cimg alt=\"GitHub tag (latest SemVer)\" src=\"https://img.shields.io/github/v/tag/elbywan/crystalline\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/elbywan/crystalline/blob/master/LICENSE\"\u003e\u003cimg alt=\"GitHub\" src=\"https://img.shields.io/github/license/elbywan/crystalline\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n\u003chr/\u003e\n\n**`Crystalline` is an implementation of the\n[Language Server Protocol](https://microsoft.github.io/language-server-protocol/)\nwritten in and for the [Crystal Language](https://crystal-lang.org/). It aims to\nprovide limited language features (like go-to, autocompletion, syntax and\nsemantic checking) and ease development with any compatible code editor.**\n\n\u003e [!IMPORTANT]\n\u003e\n\u003e ### Project Status\n\u003e\n\u003e I am **passively** maintaining this project which means that I will not be\n\u003e regularly adding new features or fixing bugs. My time is **very** limited and I have\n\u003e other projects that I want to work on.\n\u003e\n\u003e Crystalline begun as a fun experiment because at the time there was no working LSP for\n\u003e Crystal, and was written mainly to cater to my own needs - on my free time. I was happy to\n\u003e open-source it and share it with the community because I thought it could be\n\u003e useful to others.\n\u003e\n\u003e But over time, some vocal people in the Crystal community have been openly\n\u003e trash-talking the project in the (un)official discord channel, telling users\n\u003e to avoid using it and spreading misinformation, which I am not cool with.\n\u003e\n\u003e Crystalline has a bunch of issues, but if you know what you are doing, it can be a very\n\u003e useful tool. I know that because I am the primary user of it.\n\u003e\n\u003e Due to the nature of the Crystal language and the way the compiler works, it\n\u003e is not possible to provide a full-fledged language server with all the\n\u003e features that one would expect. If you have a problem\n\u003e with that, then I suggest you use another language - or wait for someone else\n\u003e to write a better LSP (which I would be happy to see, but doubt will happen).\n\u003e\n\u003e I am not paid to work on this project, I do it for fun.\n\u003e\n\u003e **And unfortunately, the fun has been sucked out of it.**\n\n\u003chr/\u003e\n\n\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"assets/small_demo.gif\" height=\"300\" width=\"360\"/\u003e\n\u003c/div\u003e\n\n## Installation\n\n_Recommended method is to download and use pre-built binaries when possible.\nBuilding from source does take a long time._\n\n### Compatibility\n\n| Crystal  | Crystalline |\n| -------- | ----------- |\n| **1.16** | **0.17**    |\n| 1.15     | 0.16        |\n| 1.14     | 0.15        |\n| 1.13     | 0.14        |\n| 1.12     | 0.13        |\n| 1.11     | 0.12        |\n| 1.10     | 0.11        |\n| 1.9      | 0.10        |\n| 1.8      | 0.9         |\n| 1.7      | 0.8         |\n| 1.6      | 0.7         |\n| 1.4      | 0.6         |\n| 1.3      | 0.5         |\n| 1.2      | 0.4         |\n| 1.1      | 0.4         |\n| 1.0      | 0.3         |\n| 0.36     | 0.2         |\n| 0.35.1   | 0.1         |\n\n### Pre-built binaries\n\n#### Latest Release\n\n##### Linux (x86_64)\n\n```sh\nwget https://github.com/elbywan/crystalline/releases/latest/download/crystalline_x86_64-unknown-linux-musl.gz -O crystalline.gz \u0026\u0026\\\ngzip -d crystalline.gz \u0026\u0026\\\nchmod u+x crystalline\n```\n\n###### ArchLinux\n\n```sh\nyay -S crystalline\n```\n\n##### MacOS\n\nInstall using [homebrew](https://brew.sh):\n\n```sh\nbrew install crystalline\n```\n\n#### Specific release\n\n[See the releases page.](https://github.com/elbywan/crystalline/releases)\n\n#### Specific commit\n\n[Binaries are uploaded as artifacts during the CI\nbuild.](https://github.com/elbywan/crystalline/actions)\n\n### Build from source\n\n**Warning: this can take a long time! (several minutes - up to 20 minutes,\ndepending on your hardware)**\n\n#### Scoped install\n\nIn the `.shard.yml` file:\n\n```yml\ndevelopment_dependencies:\n  crystalline:\n    github: elbywan/crystalline\n    branch: master\n```\n\nThen:\n\n```sh\n# Produces a binary at ./bin/crystalline\nshards build crystalline --release --no-debug --progress -Dpreview_mt\n```\n\n#### Global install\n\n```sh\ngit clone https://github.com/elbywan/crystalline\ncd crystalline\nshards install\nmkdir bin\ncrystal build ./src/crystalline.cr  -o ./bin/crystalline --release --no-debug --progress -Dpreview_mt\n```\n\n#### Known Build Issues\n\n_Potential errors when building from source._\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003ellvm-config path\u003c/strong\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n`llvm` is required in order to build `crystalline`, if you get the following\nerror message it means that the crystal compiler is unable to locate the\n`llvm-config` binary:\n\n```sh\n--: : command not found\nShowing last frame. Use --error-trace for full trace.\n\nIn /usr/local/Cellar/crystal/0.35.1/src/llvm/lib_llvm.cr:13:17\n\n 13 | VERSION = {{`#{LibLLVM::LLVM_CONFIG} --version`.chomp.stringify}}\n                  ^\nError: error executing command: \"\" --version, got exit status 127\n```\n\nThis can be solved by adding the location of the `llvm-config` binary to the\n`LLVM_CONFIG` environment variable. (or the containing directory to the `PATH`\nenv. variable)\n\nFor instance on a typical macOS setup, prefixing the command with the following\ndeclaration would solve the issue:\n\n```sh\n# Prepend the command with this:\nenv LLVM_CONFIG=/usr/local/opt/llvm/bin/llvm-config\n# For Example:\nenv LLVM_CONFIG=/usr/local/opt/llvm/bin/llvm-config crystal build ./src/crystalline.cr  -o ./bin/crystalline --release --no-debug -Dpreview_mt\n```\n\n\u003e Replace `env` by `export` on Debian and derived (Ubuntu, Mint, ...)\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003eld: library not found for -llibxml2.tbd\u003c/strong\u003e\u003c/summary\u003e\n\u003cp\u003e\n\nLLVM **10.0.1** has some issues when reporting required system libraries on\nmacOS.\n\nMore info: [here](https://github.com/ziglang/zig/issues/6087)\n\n```sh\n# Wrong: -llibxml2.tbd\n$ llvm-config --system-libs\n-lm -lz -lcurses -llibxml2.tbd\n# `liblibxml2.tbd.dylib` is unlikely to be found during compilation,\n# hence the \"library not found\" error…\n```\n\nA hacky solution until llvm produces a solution would be to add a symbolic link\nto the correct shared library file:\n\n`ln -s /usr/lib/libxml2.2.dylib /usr/local/lib/liblibxml2.tbd.dylib`\n\nOr just use a different LLVM major version until this issue is fixed upstream.\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## Usage\n\n`Crystalline` is meant to be used alongside an editor extension.\n\n#### VSCode\n\n- Add the\n  [Crystal Language extension](https://marketplace.visualstudio.com/items?itemName=crystal-lang-tools.crystal-lang).\n\n- In the configuration, type the **absolute** location of the binary in the\n  following field:\n\n![vscode screen](assets/vscode_extension_screen.png)\n\n- Reload the window by pressing CMD/CTRL + SHIFT + P and select\n  `Developer: Reload Window` (or as an alternative, restart VSCode).\n\n#### Vim/Neovim\n\nUsing Conquer of Completion we can configure Crystalline as our LSP backend and get all the features of Crystalline\nwe would get with VSCode.\n\n- Download [vim-crystal](https://github.com/vim-crystal/vim-crystal) plugin.\n- Download [CoC](https://github.com/neoclide/coc.nvim) plugin.\n- Make sure `crystalline` binary is in your PATH.\n\nAdd the following snippet to your `coc-settings.json` file:\n\n```json\n{\n\"languageserver\": {\n    \"crystal\": {\n      \"command\": \"crystalline\",\n      \"args\": [\n        \"--stdio\"\n      ],\n      \"filetypes\": [\n        \"crystal\"\n      ],\n      \"rootPatterns\": [\"shard.yml\"]\n    }\n  }\n}\n```\n\n#### Emacs\n\n- Download the `crystal-mode` [package](https://melpa.org/#/crystal-mode).\n- Download the `lsp-mode` [package](https://melpa.org/#/lsp-mode).\n- Make sure `crystalline` binary is in your PATH.\n\nAt the moment, `lsp-mode` only knows about `scry` as the Crystal language server. So, to get it working\nwith `crystalline` we need to configure `lsp-mode` to look for `crystalline`.\n\nYou can use the following config snippet to achieve this:\n```elisp\n(with-eval-after-load 'lsp-mode\n  (add-to-list 'lsp-language-id-configuration\n               '(crystal-mode . \"crystal\"))\n  (lsp-register-client\n  (make-lsp-client :new-connection (lsp-stdio-connection '(\"crystalline\"))\n                   :activation-fn (lsp-activate-on \"crystal\")\n                   :priority '1\n                   :server-id 'crystalline)))\n```\n\nThis will give higher priority to `crystalline`, and Emacs should automatically connect to the\nbackend whenever you're in `crystal-mode`.\n\n\n### Entry point\n\n**Important:** Crystalline will try to determine which file is best suited as an\nentry point when providing language features.\n\nThe default behaviour is to check the `shard.yml` file for a `target` entry\nwith the same name as the shard.\n\n```yml\nname: my_shard\n\ntargets:\n  my_shard:\n    main: src/entry.cr\n```\n\nWith the configuration above, every file required by `src/entry.cr` will use\n`src/entry.cr` as the entry point.\n\nIf this `shard.yml` entry is not present, or if the file is not part of the main\ndependency tree then `crystalline` will use the file itself as the entry point.\n\n**To override this behaviour**, you can add a configuration key in the\n`shard.yml` file.\n\n```yml\ncrystalline:\n  main: .crystalline_main.cr\n```\n\nThis can be extremely important to understand when you are writing a code\nlibrary that does not call any of its own methods - it will skip code analysis.\nIn this case, and if you are writing `specs`, you should point to a file that\nrequire the specs (or anything calling the library) and then `crystalline` will\nuse it as the entry point.\n\n```crystal\n# Contents of a file at the root of the project.\n# Will require the specs that call the library methods and enable the code analysis.\nrequire \"./spec/**\"\n```\n\n### Multiple projects\n\nIf you have multiple Crystal projects in a single folder (e.g. a monorepo), you can add a `projects` field in the root `shard.yml` file, containing an array of paths or globs to the underlying Crystal projects:\n\n```yml\ncrystalline:\n  projects:\n    - projects/my_project_1\n    - workspaces/**\n```\n\nEach of these projects must contain the `shard.yml`, ideally with the entry point as mentioned above. However, even if no entry point is present, `require`s will still be resolved relative to the project directory rather than the root directory.\n\n### Compilation flags\n\nTo use specific compilation flags, you can add a `crystalline/flags` key in the `shard.yml` file:\n\n```yml\ncrystalline:\n  flags:\n    - preview_mt\n    - execution_context\n```\n\n## Features\n\n**Disclaimer: `Crystalline` is not as extensive in terms of features as other\nLanguage Servers but still provides very convenient tools.**\n\n#### Code Diagnostics\n\nSyntax and semantic checks on save.\n\n#### Limited Autocompletion\n\nList (depending on the target) method definitions, macros or module/class/struct\nnames or symbols available in the current context.\n\n#### Formatting\n\nA whole document or a text selection.\n\n#### Go to definition\n\nBy clicking on a symbol with the Cmd or Ctrl key pressed (editor/platform\ndependent).\n\n#### Hover information\n\nHovering should display (when possible) either a variable type, a function\ndefinition signature or the expanded macro.\n\n#### Document symbols\n\nFetch all the symbols in a given file, used in VSCode to populate the Outline\nview and the Breadcrumbs.\n\n## Limitations\n\n- Memory usage is high due to the boehm GC behaviour and the crystal compiler\n  itself. See: https://github.com/elbywan/crystalline/issues/23\n\n- Due to Crystal having a wide type inference system (which is incredibly\n  convenient and practical), compilation times can unfortunately be relatively\n  long for big projects and depending on the hardware. This means that the LSP\n  will be stuck waiting for the compiler to finish before being able to provide\n  a response. Crystalline tries to mitigate that by caching compilation outcome\n  when possible.\n\n- Methods that are not called anywhere will not be analyzed, as this is how the\n  Crystal compiler works.\n\n- The parser is not permissive, nor incremental which means that the features\n  will sometimes not work. It would involve a massive amount of work to change\n  that.\n\n## Development\n\n### Dev build\n\n[Sentry](https://github.com/samueleaton/sentry) is used to re-build crystalline\nin debug mode on code change.\n\n```sh\n# To build sentry (once):\nshards build --release sentry\n# Then, to launch it and watch the filesystem:\n./bin/sentry -i\n```\n\n### Logs\n\nLogging is the most practical way to debug the LSP.\n\n```crystal\n# Use the LSP logger to display logs in the editor.\nLSP::Log.info { \"log\" }\n```\n\nDebug logs are deactivated by default, uncomment this line in\n`src/crystalline/main.cr` to enable them:\n\n```crystal\n# Uncomment:\n# ::Log.setup(:debug, LSP::Log.backend.not_nil!)\n```\n\n## Contributing\n\n1. Fork it (\u003chttps://github.com/elbywan/crystalline/fork\u003e)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n**Please always `crystal tool format` your code!**\n\n## [Contributors](https://github.com/elbywan/crystalline/graphs/contributors)\n\n## Credit\n\n- [Scry](https://github.com/crystal-lang-tools/scry), the original LSP for\n  Crystal has been a great source of inspiration. I also re-used tiny bits of\n  code from there.\n- Icon made by [Smashicons](https://www.flaticon.com/authors/smashicons) from\n  [www.flaticon.com](https://www.flaticon.com).\n\n## Trivia\n\n#### Why the name `crystalline`?\n\nAside of the obvious reasons (crystal-lang), `cristaline` is a famous bottled\nwater brand in France that published silly TV commercials. It is pronounced the\nsame as `crystalline`.\n\n![guy roux](assets/guyroux.gif)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felbywan%2Fcrystalline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felbywan%2Fcrystalline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felbywan%2Fcrystalline/lists"}