112 Commits

Author SHA1 Message Date
Myriad-Dreamin
1f8168577b wip 2026-04-20 23:10:08 +08:00
Myriad-Dreamin
60cab39f92 dev: make server public 2026-04-20 23:10:08 +08:00
Myriad-Dreamin
67bedd1ae0 dev: index nodes 2026-04-20 23:10:08 +08:00
Myriad-Dreamin
7ab8ad9513 fix: crash 2026-04-20 23:10:08 +08:00
Myriad-Dreamin
c11178fd77 dev: builtin lib 2026-04-20 23:10:08 +08:00
Myriad-Dreamin
150f47c590 hardcode clang 2026-04-20 23:10:08 +08:00
Myriad-Dreamin
b7987fded3 dev: workaround cc1 compilation 2026-01-26 17:45:00 +08:00
Myriad-Dreamin
44a4bd4107 dev: index notify 2026-01-26 17:44:47 +08:00
Myriad-Dreamin
044e4c4b27 feat: implement serialize for optional 2026-01-26 17:44:47 +08:00
Myriad-Dreamin
68eb63ba04 ActiveFile 2026-01-26 17:44:47 +08:00
Myriad-Dreamin
39d3648fdd feat: add method to check indices size 2026-01-26 17:43:16 +08:00
Myriad-Dreamin
6640c05d66 build: cannot build cpptrace 2026-01-26 17:43:16 +08:00
Myriad-Dreamin
69ac764ef2 feat: split copy_headers for external builds 2026-01-26 17:43:16 +08:00
Myriad-Dreamin
04c6ca5337 fix: correct server ref impl 2026-01-26 17:43:16 +08:00
Myriad-Dreamin
2408978d2d fix: correct plugin_paths decl 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
74f75f107f fix: compile error 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
0e2e487bc9 feat: introduce any type alias for llvm::json::Value 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
6be48bccd2 feat: implement dummy workspace/executeCommand 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
4262734d21 dev: simplify protocol def 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
ed0d7db3db dev: simplify protocol def 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
824b305f93 dev: simplify protocol def 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
f89793c66d dev: more lifetime hooks 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
4425fb5244 dev: simplify 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
25a85a3b8e feat: implement apis 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
0f95344abe fix: typo 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
3511915886 dev: remove useless comments 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
6e50451c43 fix: typo 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
99d9363b95 fix: paths 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
7533d4d15e docs: compile and laod plugin sections 2026-01-26 01:01:39 +08:00
Myriad-Dreamin
a118c16e96 feat: add minimal support to clice server plugins 2026-01-26 01:01:39 +08:00
ykiko
c0ffd2369b refactor: unify the CompilationUnitRef usage (#346) 2026-01-12 00:21:35 +08:00
Myriad-Dreamin
d6733dd43d feat: replace compile_commands_dirs with compile_commands_paths (#343) 2026-01-10 23:23:32 +08:00
Myriad-Dreamin
53689f2256 fix: prevent bad argument pop back when querying toolchain (#342) 2026-01-10 22:43:47 +08:00
Myriad-Dreamin
f30f68f573 fix: compiling C source file without -std=c++20 (#334) 2026-01-07 23:13:21 +08:00
ykiko
dd8f0dd90d refactor: diagnostic handling (#337) 2026-01-03 16:23:06 +08:00
ykiko
dee5e136b7 fix: docs spelling and workflow check (#336) 2026-01-01 00:48:14 +08:00
ykiko
4d16cf7b0a docs: update build (#335) 2026-01-01 00:36:07 +08:00
Myriad-Dreamin
c6d87cccf3 fix: stuck caused by Network:on_read (#333) 2025-12-29 22:58:47 +08:00
ykiko
aa3e5111de fix: only publish when a tag is created (#332) 2025-12-29 11:55:18 +08:00
ykiko
7a29560065 build: optimize the workflow (#331) 2025-12-29 09:19:45 +08:00
ykiko
7105e36803 chore: use pixi to manage the format tools and format the world (#330) 2025-12-28 19:36:06 +08:00
star9029
bc523b0681 build: use pixi in package ci (#326) 2025-12-21 16:47:42 +08:00
star9029
b8da7e79db build: use pixi in ci (#325)
Co-authored-by: ykiko <ykikoykikoykiko@gmail.com>
2025-12-17 13:04:02 +08:00
ykiko
1da34574c9 build: use pixi for managing build toolchains (#322) 2025-12-16 01:53:25 +08:00
ykiko
cec13ec29b refactor: tests and format the world (#314) 2025-11-30 15:21:27 +08:00
ykiko
2214d53ea5 chore: simplify config file (#319) 2025-11-28 02:07:06 +08:00
ykiko
8f74adf2b9 extension: migrate zed to editors/ (#318) 2025-11-28 01:46:51 +08:00
ykiko
2c11be9365 extension: migrate nvim to editors/ (#317) 2025-11-28 01:46:37 +08:00
ykiko
caf9a172d6 extension: migrate vscode to editors/ (#316) 2025-11-28 00:37:22 +08:00
ykiko
8aff090a08 refactor: incremental update for compilation database and introduce query toolchain (#311) 2025-11-23 18:43:36 +08:00
ykiko
f16867902c build: update package workflow (#307)
Co-authored-by: star9029 <hengxings783@gmail.com>
2025-11-17 00:45:44 +08:00
Shiyu
4d07bad2f2 build: add guard for clang-tidy-config.h in xmake rules (#306)
Co-authored-by: ykiko <ykikoykikoykiko@gmail.com>
2025-11-16 02:32:00 +08:00
ykiko
4a2a6aa65a build: update llvm checksum and refactor ci (#304) 2025-11-16 02:17:37 +08:00
star9029
3c53d3bc72 build: update llvm 21.1.4 checksum (#303) 2025-11-09 11:35:03 +08:00
ykiko
9e1039f861 refactor: improve logging (#301) 2025-11-08 00:37:07 +08:00
star9029
8a2ef62596 build: enable xmake ci package cache (#295) 2025-11-05 23:33:28 +08:00
ykiko
336ca639f0 refactor: CompilationDatabase and scan (#286) 2025-11-05 23:01:28 +08:00
ClSlaid
9c43285d0d fix: xmake spdlog force non-system (#299)
Signed-off-by: 蔡略 <cailue@apache.org>
2025-11-05 20:56:15 +08:00
ykiko
39ec9bf7c5 fix: reset clang dependency output options (#293) 2025-11-02 23:25:39 +08:00
ykiko
397eb71dad build: update llvm to 21.1.4 (#292) 2025-11-02 22:23:11 +08:00
Myriad-Dreamin
3b1e379408 Fix warnings in Compiler (#290) 2025-10-31 20:52:16 +08:00
Myriad-Dreamin
8b998e658c [Fix] Use server's encoding kind (#289) 2025-10-31 20:51:11 +08:00
Myriad-Dreamin
9806e45fa3 [Feature] Enable clang-tidy (#200)
Co-authored-by: star9029 <hengxings783@gmail.com>
2025-10-31 20:50:07 +08:00
Perdixky
7d71c0f689 [Fix] GCC compilation issue caused by template specialization (#287) 2025-10-29 09:45:42 +08:00
ykiko
a10908d3d9 Fix release ci (#282)
Co-authored-by: star9029 <hengxings783@gmail.com>
2025-10-20 21:43:46 +08:00
ykiko
dffa884e5a Store indices to disk (#279) 2025-10-19 21:53:57 +08:00
qingfengzl
eda7f03a37 Fix logging color (#276) 2025-10-10 22:23:09 +08:00
ykiko
9674328c18 Add ProjectIndex and basic symbol lookup implementation (#274) 2025-10-08 16:39:50 +08:00
ykiko
4c63c52487 Serialize index to binary (#273) 2025-10-07 18:21:44 +08:00
ykiko
b705560557 Introduce flatbuffer (#272)
Co-authored-by: star9029 <hengxings783@gmail.com>
2025-10-06 13:10:29 +08:00
ykiko
49caa2d9ba FileIndex and MergedIndex for clice (#271) 2025-10-05 22:46:32 +08:00
ykiko
4a184a26ce Fix unit_test fail doesn't result in error in CI (#270) 2025-10-03 14:50:38 +08:00
ykiko
9569988509 Fix query driver on windows (#269) 2025-10-03 03:26:21 +08:00
ykiko
7cd20c8565 Add remove and append options for CompilationDatabase (#268) 2025-10-02 18:00:01 +08:00
qingfengzl
2b350400bd Fix unit test of driver query (#267) 2025-09-27 11:13:39 +08:00
tang donghai
afe808274b Update LLVM build configuration to include clang-tools-extra project (#266) 2025-09-25 22:37:16 +08:00
qingfengzl
e5348bd305 Fix glob pattern (#263) 2025-09-20 23:10:31 +08:00
sora-mono
f94927dc1d Dev Container Support (#248)
Co-authored-by: star9029 <hengxings783@gmail.com>
2025-09-19 23:28:36 +08:00
fogsong233
4953e7ac49 Fix typo (#260) 2025-09-15 22:03:26 +08:00
ykiko
bba3ee3174 Remove config option and read config file from ${workspace}/clice.toml (#258) 2025-09-14 22:42:02 +08:00
ykiko
50ef22f197 Fix npm security (#256) 2025-09-14 17:20:06 +08:00
ykiko
e8f5f6ba64 Allow log output to a file (#252)
Co-authored-by: star9029 <hengxings783@gmail.com>
2025-09-14 16:45:07 +08:00
zaragoza
d502eee53f Fix query driver on Windows (#255)
Co-authored-by: zaragoza-xu <xuyiyan920@gmail.com>
2025-09-11 00:10:54 +08:00
ykiko
2ffab4fdff Remove .html suffix of docs (#249) 2025-09-09 10:49:51 +08:00
ykiko
f65876903c Improve integration test (#246) 2025-09-09 02:03:59 +08:00
sora-mono
83c6b2d60d Support msvc build CMake (#233) 2025-09-07 23:30:46 +08:00
ykiko
3cc3bae441 Format and simplify intergration test (#245) 2025-09-07 23:27:39 +08:00
Myriad-Dreamin
5e273415ee Implement isRegisteredTidyCheck and isFastTidyCheck (#204) 2025-09-07 14:22:52 +08:00
Myriad-Dreamin
9ec4e0651a Documenting GCC toolchain settings (#231)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: star9029 <hengxings783@gmail.com>
2025-09-06 20:27:38 +08:00
zaragoza
5786d852f2 Record the time of handling request and notification (#236)
Co-authored-by: zaragoza-xu <xuyiyan920@gmail.com>
2025-09-06 16:29:29 +08:00
Myriad-Dreamin
0c0e898dac Fix ruff python warning (#230) 2025-09-06 16:24:57 +08:00
Myriad-Dreamin
658c33a01f Init clang tidy (#195) 2025-09-06 16:23:20 +08:00
Myriad-Dreamin
0d56dbf192 Install clice executable in CMakeLists.txt (#229) 2025-09-06 16:22:10 +08:00
Myriad-Dreamin
a942279765 Build clice container (#196) 2025-09-06 16:21:28 +08:00
star9029
9e55381788 Improve build (#226) 2025-09-06 00:40:55 +08:00
ykiko
9eb0803d10 Fix org name and update README (#235) 2025-09-06 00:07:34 +08:00
ykiko
33cf288bcc Update LICENSE (#234) 2025-09-05 23:11:39 +08:00
sora-mono
bd0ead226b Fix/support build with msvc (#214) 2025-09-03 22:21:49 +08:00
ClSlaid
cb3bfd54f9 [CI] Dowload prebuilt llvm in cmake (#192)
Signed-off-by: 蔡略 <cailue@apache.org>
Co-authored-by: ykiko <ykikoykikoykiko@gmail.com>
2025-09-03 22:05:45 +08:00
Shiyu
c6db056af6 Update documents, add RPATH for LLVM dynamic libraries in xmake.lua (#221) 2025-09-03 20:35:08 +08:00
Shiyu
7beed982f2 Fix: store absolute path of source file in CompilationDatabase (#222) 2025-09-03 20:34:02 +08:00
Shiyu
155773cf66 Feat: better load and fetch compile command (#201)
Co-authored-by: ykiko <ykikoykikoykiko@gmail.com>
2025-09-02 22:12:05 +08:00
miyanyan
8337475b91 add CONFIGURE_DEPENDS to cmake file GLOB_RECURSE (#213) 2025-09-01 21:46:45 +08:00
Lucas Pingas
31e4c039d2 Add Bazel instructions to quick-start.md (#215)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: ykiko <ykikoykikoykiko@gmail.com>
2025-09-01 21:17:48 +08:00
ykiko
85de68ca79 Fix prebuilt macos (#217) 2025-09-01 21:05:03 +08:00
Myriad-Dreamin
bcd40b239d Also Handle InitializeParams::rootUri (#212) 2025-08-29 22:52:15 +08:00
star9029
41320e866c Fix resource dir for xmake (#211) 2025-08-29 22:28:18 +08:00
star9029
2fb36b7251 Fix release ci (#210) 2025-08-28 23:40:19 +08:00
ykiko
f4d5493d6f Update README (#206) 2025-08-26 22:45:54 +08:00
ykiko
d3a4550309 Update README (#205) 2025-08-26 22:35:50 +08:00
Myriad-Dreamin
90d424b72a Init uv project for pytest (#193)
Co-authored-by: star9029 <hengxings783@gmail.com>
2025-08-26 00:05:50 +08:00
Shiyu
260c268af7 Fix: improve some case that user's environment do not have driver installed (#185) 2025-08-24 19:46:22 +08:00
358 changed files with 30944 additions and 15581 deletions

View File

@@ -1,5 +1,4 @@
# clang-format configuration
# compatible with clang-format 18
UseTab: Never
ColumnLimit: 100
@@ -73,7 +72,7 @@ SpaceBeforeParensOptions:
AfterFunctionDeclarationName: false
AfterFunctionDefinitionName: false
AfterIfMacros: false
AfterOverloadedOperator: true
AfterOverloadedOperator: false
AfterRequiresInClause: true
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
@@ -93,11 +92,50 @@ SpacesInParensOptions:
SpacesInSquareBrackets: false
WrapNamespaceBodyWithEmptyLines: Always
# Order
QualifierAlignment: Custom
QualifierOrder: ["constexpr", "const", "inline", "static", "type"]
SortIncludes: Never
SortIncludes: true
SortUsingDeclarations: Never
IncludeBlocks: Merge
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^["<](spdlog|toml\+\+|coraing|cpptrace|flatbuffers)/'
Priority: 30
SortPriority: 31
- Regex: '^["<](llvm)/'
Priority: 30
SortPriority: 32
- Regex: '^["<](clang)/'
Priority: 30
SortPriority: 33
- Regex: '^["<](clang-tidy)/'
Priority: 30
SortPriority: 34
- Regex: '^["<](Test)/'
Priority: 20
SortPriority: 22
- Regex: "^<.*"
Priority: 10
SortPriority: 10
- Regex: '^".*/.*"'
Priority: 20
SortPriority: 23
- Regex: ".*"
Priority: 20
SortPriority: 21
ForEachMacros: ["REFLECTABLE_RECORD"]
NamespaceMacros: [TEST_SUITE]
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: false
AtStartOfFile: false

View File

@@ -1,2 +0,0 @@
Diagnostics:
UnusedIncludes: None

2
.coderabbit.yaml Normal file
View File

@@ -0,0 +1,2 @@
chat:
auto_reply: false

0
.codex Normal file
View File

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# SCM syntax highlighting & preventing 3-way merges
pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff

View File

@@ -1,10 +1,9 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
title: ""
labels: ""
assignees: ""
---
**Describe the bug**
@@ -12,6 +11,7 @@ A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
@@ -24,15 +24,17 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@@ -1,10 +1,9 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
title: ""
labels: ""
assignees: ""
---
**Is your feature request related to a problem? Please describe.**

20
.github/actions/setup-pixi/action.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: "Setup Pixi"
description: "setup pixi"
inputs:
environments:
description: "The pixi environments to install (e.g. default, docs, test)"
required: false
default: "default"
runs:
using: "composite"
steps:
- name: Setup Pixi
uses: prefix-dev/setup-pixi@v0.9.3
with:
pixi-version: v0.62.0
environments: ${{ inputs.environments }}
activate-environment: true
cache: true
locked: true

191
.github/workflows/build-llvm.yml vendored Normal file
View File

@@ -0,0 +1,191 @@
name: build llvm
on:
pull_request:
# if you want to run this workflow, change the branch name to main,
# if you want to turn off it, change it to non existent branch.
branches: [main-turn-off]
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: windows-2025
llvm_mode: Debug
lto: OFF
- os: windows-2025
llvm_mode: RelWithDebInfo
lto: OFF
- os: windows-2025
llvm_mode: RelWithDebInfo
lto: ON
- os: ubuntu-24.04
llvm_mode: Debug
lto: OFF
- os: ubuntu-24.04
llvm_mode: RelWithDebInfo
lto: OFF
- os: ubuntu-24.04
llvm_mode: RelWithDebInfo
lto: ON
- os: macos-15
llvm_mode: Debug
lto: OFF
- os: macos-15
llvm_mode: RelWithDebInfo
lto: OFF
- os: macos-15
llvm_mode: RelWithDebInfo
lto: ON
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Free Disk Space
if: runner.os == 'Linux'
uses: jlumbroso/free-disk-space@main
- name: Increase Swap Space
if: runner.os == 'Linux'
run: |
echo "===== Initial Status ====="
sudo swapon --show
free -h
echo "===== Creating Swap File ====="
sudo swapoff -a
sudo fallocate -l 16G /mnt/swapfile
sudo chmod 600 /mnt/swapfile
sudo mkswap /mnt/swapfile
sudo swapon /mnt/swapfile
echo "===== Final Status ====="
sudo swapon --show
free -h
df -h
- name: Setup Pixi
uses: prefix-dev/setup-pixi@v0.9.3
with:
pixi-version: v0.59.0
environments: package
activate-environment: true
cache: true
locked: true
- name: Clone llvm-project (21.1.4)
shell: bash
run: |
git clone --branch llvmorg-21.1.4 --depth 1 https://github.com/llvm/llvm-project.git .llvm
- name: Build LLVM (install-distribution)
shell: bash
run: |
pixi run build-llvm --llvm-src=.llvm --mode="${{ matrix.llvm_mode }}" --lto="${{ matrix.lto }}" --build-dir=build
- name: Build clice using installed LLVM
shell: bash
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=${{ matrix.llvm_mode }} \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain.cmake \
-DCLICE_ENABLE_TEST=ON \
-DCLICE_CI_ENVIRONMENT=ON \
-DCLICE_ENABLE_LTO=${{ matrix.lto }} \
-DLLVM_INSTALL_PATH=".llvm/build-install"
cmake --build build
- name: Run tests
shell: bash
run: |
EXE_EXT=""
if [[ "${{ runner.os }}" == "Windows" ]]; then
EXE_EXT=".exe"
fi
./build/bin/unit_tests${EXE_EXT} --test-dir="./tests/data"
uv run --project tests pytest -s --log-cli-level=INFO tests/integration --executable=./build/bin/clice${EXE_EXT}
- name: Prune LLVM static libraries (Debug/RelWithDebInfo no LTO)
if: matrix.llvm_mode == 'Debug' || (matrix.llvm_mode == 'RelWithDebInfo' && matrix.lto == 'OFF')
shell: bash
run: |
MANIFEST="pruned-libs-${{ matrix.os }}.json"
echo "LLVM_PRUNED_MANIFEST=${MANIFEST}" >> "${GITHUB_ENV}"
python3 scripts/prune-llvm-bin.py \
--action discover \
--install-dir ".llvm/build-install/lib" \
--build-dir "build" \
--max-attempts 60 \
--sleep-seconds 60 \
--manifest "${MANIFEST}"
- name: Upload pruned-libs manifest
if: matrix.llvm_mode == 'RelWithDebInfo' && matrix.lto == 'OFF'
uses: actions/upload-artifact@v4
with:
name: llvm-pruned-libs-${{ matrix.os }}
path: ${{ env.LLVM_PRUNED_MANIFEST }}
if-no-files-found: error
compression-level: 0
- name: Apply pruned-libs manifest (RelWithDebInfo + LTO)
if: matrix.llvm_mode == 'RelWithDebInfo' && matrix.lto == 'ON'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
MANIFEST="pruned-libs-${{ matrix.os }}.json"
python3 scripts/prune-llvm-bin.py \
--action apply \
--manifest "${MANIFEST}" \
--install-dir ".llvm/build-install/lib" \
--build-dir "build" \
--gh-run-id "${{ github.run_id }}" \
--gh-artifact "llvm-pruned-libs-${{ matrix.os }}" \
--gh-download-dir "artifacts" \
--max-attempts 60 \
--sleep-seconds 60
- name: Package LLVM install directory
shell: bash
run: |
MODE_TAG="releasedbg"
if [[ "${{ matrix.llvm_mode }}" == "Debug" ]]; then
MODE_TAG="debug"
fi
ARCH="x64"
PLATFORM="linux"
TOOLCHAIN="gnu"
if [[ "${{ matrix.os }}" == windows-* ]]; then
PLATFORM="windows"
TOOLCHAIN="msvc"
elif [[ "${{ matrix.os }}" == macos-* ]]; then
ARCH="arm64"
PLATFORM="macos"
TOOLCHAIN="clang"
fi
SUFFIX=""
if [[ "${{ matrix.lto }}" == "ON" ]]; then
SUFFIX="-lto"
fi
if [[ "${{ matrix.llvm_mode }}" == "Debug" ]]; then
SUFFIX="${SUFFIX}-asan"
fi
ARCHIVE="${ARCH}-${PLATFORM}-${TOOLCHAIN}-${MODE_TAG}${SUFFIX}.tar.xz"
set -eo pipefail
tar -C .llvm -cf - build-install | xz -T0 -9 -c > "${ARCHIVE}"
echo "LLVM_INSTALL_ARCHIVE=${ARCHIVE}" >> "${GITHUB_ENV}"
- name: Upload LLVM install artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.LLVM_INSTALL_ARCHIVE }}
path: ${{ env.LLVM_INSTALL_ARCHIVE }}
if-no-files-found: error

View File

@@ -1,47 +1,33 @@
name: format
on:
push:
branches: [main]
paths:
- .clang-format
- "include/**"
- "src/**"
- "tests/**"
pull_request:
branches: [main]
paths:
- .clang-format
- "include/**"
- "src/**"
- "tests/**"
workflow_call:
jobs:
check:
check-format:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install clang-format
run: |
wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/llvm.asc
echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main" | sudo tee /etc/apt/sources.list.d/llvm20.list
echo "deb-src http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main" | sudo tee -a /etc/apt/sources.list.d/llvm20.list
sudo apt-get update && sudo apt-get install -y clang-format-20
clang-format-20 --version
- uses: ./.github/actions/setup-pixi
with:
environments: format
- name: Run clang-format check
run: |
FILES=$(find ./ -type f | grep -P '^\.\/(src|include)(\/[^\/]+)*\/[^\/]+\.(h|cpp|cc)$')
- name: Run formatter
run: pixi run format
continue-on-error: true
UNFORMATTED=$(clang-format-20 --dry-run --Werror $FILES)
- name: Auto correct
uses: huacnlee/autocorrect-action@v2
with:
args: --lint ./docs
continue-on-error: true
if [ $? -ne 0 ]; then
echo "× Some files are not properly formatted. Run clang-format to fix them."
exit 1
else
echo "✓ All files are properly formatted."
fi
- name: Suggest changes
if: github.event_name == 'pull_request'
uses: reviewdog/action-suggester@v1.24.0
with:
tool_name: "fmt"
fail_level: any
filter_mode: nofilter

View File

@@ -1,122 +0,0 @@
name: cmake
on:
push:
branches: [main]
paths:
- ".github/workflows/cmake.yml"
- "include/**"
- "src/**"
- "tests/**"
- "CMakeLists.txt"
pull_request:
branches: [main]
paths:
- ".github/workflows/cmake.yml"
- "include/**"
- "src/**"
- "tests/**"
- "CMakeLists.txt"
jobs:
build:
strategy:
matrix:
os: [ubuntu-24.04, windows-2025, macos-15]
runs-on: ${{ matrix.os }}
steps:
- name: Setup ninja
if: matrix.os == 'windows-2025'
uses: MinoruSekine/setup-scoop@v4.0.1
with:
buckets: main
apps: ninja
- name: Setup llvm & libstdc++ & cmake & ninja
if: matrix.os == 'ubuntu-24.04'
run: |
sudo apt update
sudo apt install -y gcc-14 g++-14 libstdc++-14-dev
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100
sudo update-alternatives --set gcc /usr/bin/gcc-14
sudo update-alternatives --set g++ /usr/bin/g++-14
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 20 all
sudo apt install -y cmake ninja-build
- name: Setup llvm@20 and lld
if: matrix.os == 'macos-15'
run: |
brew install llvm@20 lld@20
- name: Set up Python
if: matrix.os == 'windows-2025'
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup llvm binary
if: matrix.os == 'windows-2025'
run: |
curl -O -L "https://github.com/clice-project/llvm-binary/releases/download/20.1.5/x64-windows-msvc-release.7z"
7z x x64-windows-msvc-release.7z "-o.llvm"
- name: Setup llvm binary
if: matrix.os == 'ubuntu-24.04'
run: |
mkdir -p ./.llvm
curl -L "https://github.com/clice-project/llvm-binary/releases/download/20.1.5/x86_64-linux-gnu-debug.tar.xz" | tar -xJ -C ./.llvm
- name: Setup llvm binary
if: matrix.os == 'macos-15'
run: |
mkdir -p ./.llvm
curl -L "https://github.com/clice-project/llvm-binary/releases/download/20.1.5/arm64-macosx-apple-debug.tar.xz" | tar -xJ -C ./.llvm
- name: Setup msvc sysroot for cmake
if: matrix.os == 'windows-2025'
uses: ilammy/msvc-dev-cmd@v1
- name: Build clice (release, windows)
if: matrix.os == 'windows-2025'
run: |
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_INSTALL_PATH="./.llvm" -DCLICE_ENABLE_TEST=ON
cmake --build build
- name: Build clice (debug, linux)
if: matrix.os == 'ubuntu-24.04'
run: |
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DLLVM_INSTALL_PATH="./.llvm" -DCLICE_ENABLE_TEST=ON
cmake --build build
- name: Build clice (debug, macos)
if: matrix.os == 'macos-15'
run: |
export PATH="/opt/homebrew/opt/llvm@20/bin:/opt/homebrew/opt/lld@20/bin:$PATH"
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_INSTALL_PATH="./.llvm" -DCLICE_ENABLE_TEST=ON
cmake --build build
- name: Install Python dependencies
run: pip install pytest pytest-asyncio pytest-xdist
- name: Run tests
if: matrix.os == 'windows-2025'
run: |
./build/bin/unit_tests.exe --test-dir="./tests/data" --resource-dir="./.llvm/lib/clang/20"
pytest -s --log-cli-level=INFO tests/integration --executable=./build/bin/clice.exe --resource-dir="./.llvm/lib/clang/20"
- name: Run tests
if: matrix.os == 'ubuntu-24.04' || matrix.os == 'macos-15'
run: |
./build/bin/unit_tests --test-dir="./tests/data" --resource-dir="./.llvm/lib/clang/20"
pytest -s --log-cli-level=INFO tests/integration --executable=./build/bin/clice --resource-dir="./.llvm/lib/clang/20"

28
.github/workflows/deploy-docs.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: deploy
on:
workflow_call:
jobs:
deploy-docs:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: ./.github/actions/setup-pixi
with:
environments: node
- name: Build docs
run: pixi run build-docs
- name: Deploy to GitHub Pages
if: github.ref == 'refs/heads/main'
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/.vitepress/dist
cname: clice.io

View File

@@ -1,43 +0,0 @@
name: deploy
on:
push:
branches: [main]
paths:
- "docs/**"
- ".github/workflows/deploy.yml"
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
cache-dependency-path: docs/package-lock.json
- name: Install dependencies in docs
run: |
cd docs
npm install
- name: Build docs
run: |
cd docs
npm run docs:build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/.vitepress/dist
cname: clice.io

123
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,123 @@
name: main
on:
push:
branches: [main]
tags: ["v*"]
pull_request:
branches: [main]
jobs:
changes:
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
format: ${{ steps.filter.outputs.format }}
docs: ${{ steps.filter.outputs.docs }}
clice: ${{ steps.filter.outputs.clice }}
vscode: ${{ steps.filter.outputs.vscode }}
cmake: ${{ steps.filter.outputs.cmake }}
xmake: ${{ steps.filter.outputs.xmake }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
format:
- '**/*.{h,c,cpp,hpp,ts,js,lua,md,yml,yaml}'
docs:
- 'docs/**'
- '.github/workflows/deploy-docs.yml'
clice:
- 'src/**'
- 'include/**'
- 'CMakeLists.txt'
- '.github/workflows/publish-clice.yml'
vscode:
- 'editors/vscode/**'
- '.github/workflows/publish-vscode.yml'
cmake:
- 'CMakeLists.txt'
- 'src/**'
- 'include/**'
- 'tests/**'
- 'config/**'
- '.github/workflows/test-cmake.yml'
xmake:
- 'xmake.lua'
- 'src/**'
- 'include/**'
- 'tests/**'
- 'config/**'
- '.github/workflows/test-xmake.yml'
format:
needs: changes
permissions:
contents: read
checks: write
issues: write
pull-requests: write
if: ${{ needs.changes.outputs.format == 'true' }}
uses: ./.github/workflows/check-format.yml
deploy:
needs: changes
if: ${{ needs.changes.outputs.docs == 'true' }}
permissions:
contents: write
uses: ./.github/workflows/deploy-docs.yml
clice:
needs: changes
if: ${{ needs.changes.outputs.clice == 'true' }}
uses: ./.github/workflows/publish-clice.yml
vscode:
needs: changes
if: ${{ needs.changes.outputs.vscode == 'true' }}
uses: ./.github/workflows/publish-vscode.yml
cmake:
needs: changes
if: ${{ needs.changes.outputs.cmake == 'true' }}
uses: ./.github/workflows/test-cmake.yml
xmake:
needs: changes
if: ${{ needs.changes.outputs.xmake == 'true' }}
uses: ./.github/workflows/test-xmake.yml
release-clice:
permissions:
contents: write
if: startsWith(github.ref, 'refs/tags/v')
uses: ./.github/workflows/publish-clice.yml
secrets: inherit
release-vscode:
permissions:
contents: write
if: startsWith(github.ref, 'refs/tags/v')
uses: ./.github/workflows/publish-vscode.yml
secrets: inherit
checks-passed:
if: ${{ always() && !startsWith(github.ref, 'refs/tags/') }}
needs:
- format
- deploy
- clice
- vscode
- cmake
- xmake
runs-on: ubuntu-latest
steps:
- name: Check results
uses: re-actors/alls-green@release/v1
with:
allowed-skips: format,deploy,clice,vscode,cmake,xmake
jobs: ${{ toJSON(needs) }}

79
.github/workflows/publish-clice.yml vendored Normal file
View File

@@ -0,0 +1,79 @@
name: clice
on:
workflow_call:
jobs:
publish-clice:
strategy:
fail-fast: false
matrix:
include:
- os: windows-2025
artifact_name: clice.zip
asset_name: clice-x64-windows-msvc.zip
symbol_artifact_name: clice-symbol.zip
symbol_asset_name: clice-x64-windows-msvc-symbol.zip
- os: ubuntu-24.04
artifact_name: clice.tar.gz
asset_name: clice-x86_64-linux-gnu.tar.gz
symbol_artifact_name: clice-symbol.tar.gz
symbol_asset_name: clice-x86_64-linux-gnu-symbol.tar.gz
- os: macos-15
artifact_name: clice.tar.gz
asset_name: clice-arm64-macos-darwin.tar.gz
symbol_artifact_name: clice-symbol.tar.gz
symbol_asset_name: clice-arm64-macos-darwin-symbol.tar.gz
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: 3.0.5
actions-cache-folder: ".xmake-cache"
actions-cache-key: ${{ matrix.os }}
package-cache: true
package-cache-key: ${{ matrix.os }}-pkg-release-v1
build-cache: true
build-cache-key: ${{ matrix.os }}-build-release-v1
- uses: ./.github/actions/setup-pixi
with:
environments: package
- name: Remove ci llvm toolchain on Windows
if: runner.os == 'Windows'
run: |
# @see https://github.com/xmake-io/xmake/issues/7158
xmake lua os.rmdir "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/Llvm"
xmake lua os.rmdir "C:/Program Files/LLVM"
- name: Package
run: pixi run package
- name: Upload Main Package to Release
if: startsWith(github.ref, 'refs/tags/v')
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/xpack/clice/${{ matrix.artifact_name }}
asset_name: ${{ matrix.asset_name }}
tag: ${{ github.ref }}
overwrite: true
- name: Upload Symbol Package to Release
if: startsWith(github.ref, 'refs/tags/v')
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/xpack/clice/${{ matrix.symbol_artifact_name }}
asset_name: ${{ matrix.symbol_asset_name }}
tag: ${{ github.ref }}
overwrite: true

38
.github/workflows/publish-vscode.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: vscode
on:
workflow_call:
jobs:
publish-vscode:
runs-on: ubuntu-latest
defaults:
run:
working-directory: editors/vscode
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: ./.github/actions/setup-pixi
with:
environments: node
- name: Publish and Package to Marketplace
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}
run: |
FLAG="${{ contains(github.ref_name, '-') && '--pre-release' || '' }}"
pixi run build-vscode $FLAG
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
pixi run publish-vscode -p "$VSCE_PAT" $FLAG
fi
- name: Upload .vsix to Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/v')
with:
files: "editors/vscode/*.vsix"
tag_name: ${{ github.ref }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,91 +0,0 @@
name: release
permissions:
contents: write
on:
push:
tags:
- 'v*'
jobs:
package:
strategy:
matrix:
include:
- os: windows-2022
artifact_name: clice.7z
asset_name: clice-x64-windows-msvc.7z
toolchain: clang
- os: ubuntu-24.04
artifact_name: clice.tar.xz
asset_name: clice-x86_64-linux-gnu.tar.xz
toolchain: clang-20
- os: macos-15
artifact_name: clice.tar.xz
asset_name: clice-arm64-macos-darwin.tar.xz
toolchain: clang
runs-on: ${{ matrix.os }}
steps:
- name: Setup llvm
if: matrix.os == 'windows-2022'
uses: MinoruSekine/setup-scoop@v4.0.1
with:
buckets: main
apps: llvm
- name: Setup llvm & libstdc++ & cmake & ninja
if: matrix.os == 'ubuntu-24.04'
run: |
sudo apt remove llvm-16-linker-tools llvm-16 llvm-17-linker-tools llvm-17 llvm-18-linker-tools llvm-18
sudo apt update
sudo apt install -y gcc-14 g++-14 libstdc++-14-dev cmake ninja-build
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100
sudo update-alternatives --set gcc /usr/bin/gcc-14
sudo update-alternatives --set g++ /usr/bin/g++-14
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 20 all
- name: Setup llvm@20
if: matrix.os == 'macos-15'
run: |
brew install llvm@20
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: branch@master
actions-cache-folder: ".xmake-cache"
actions-cache-key: ${{ matrix.os }}
- name: Package
if: matrix.os != 'macos-15'
run: |
xmake config --yes --toolchain=${{ matrix.toolchain }} --enable_test=n --dev=n --release=y
xmake pack
- name: Package
if: matrix.os == 'macos-15'
run: |
xmake config --yes --toolchain=${{ matrix.toolchain }} --sdk=/opt/homebrew/opt/llvm@20 --enable_test=n --dev=n --release=y
xmake pack
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/xpack/clice/${{ matrix.artifact_name }}
asset_name: ${{ matrix.asset_name }}
tag: ${{ github.ref }}
overwrite: true

29
.github/workflows/test-cmake.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: cmake
on:
workflow_call:
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: windows-2025
build_type: RelWithDebInfo
- os: ubuntu-24.04
build_type: Debug
- os: macos-15
build_type: Debug
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: ./.github/actions/setup-pixi
- name: Build
run: pixi run build ${{ matrix.build_type }} ON
- name: Test
run: pixi run test ${{ matrix.build_type }}

42
.github/workflows/test-xmake.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: xmake
on:
workflow_call:
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [windows-2025, ubuntu-24.04, macos-15]
build_type: [debug, releasedbg]
exclude:
- os: windows-2025
build_type: debug
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: 3.0.5
actions-cache-folder: ".xmake-cache"
actions-cache-key: ${{ matrix.os }}
package-cache: true
package-cache-key: ${{ matrix.os }}-pixi
build-cache: true
build-cache-key: ${{ matrix.os }}-${{ matrix.build_type }}
- uses: ./.github/actions/setup-pixi
- name: Build
run: pixi run xmake ${{ matrix.build_type }}
- name: Test
run: pixi run xmake-test
- name: Remove llvm package (Linux)
if: runner.os == 'Linux'
run: xmake require --uninstall clice-llvm

38
.github/workflows/upload-llvm.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: upload-llvm
permissions:
contents: write
on:
pull_request:
# if you want to run this workflow, change the branch name to main,
# if you want to turn off it, change it to non existent branch.
branches: [main-turn-off]
workflow_dispatch:
inputs:
workflow_id:
description: "Workflow run ID to pull artifacts from"
required: true
type: string
version:
description: "Release version/tag to publish (e.g., v1.2.3)"
required: true
type: string
jobs:
upload:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Download artifacts from workflow
env:
GH_TOKEN: ${{ github.token }}
run: scripts/download-llvm.sh "${{ inputs.workflow_id }}"
- name: Recreate release with artifacts
env:
GH_TOKEN: ${{ secrets.UPLOAD_LLVM }}
TARGET_REPO: clice-io/clice-llvm
run: python3 scripts/upload-llvm.py "${{ inputs.version }}" "${TARGET_REPO}" "${{ inputs.workflow_id }}"

View File

@@ -1,144 +0,0 @@
name: xmake
on:
push:
branches: [main]
paths:
- ".github/workflows/xmake.yml"
- "include/**"
- "src/**"
- "tests/**"
- "xmake.lua"
pull_request:
branches: [main]
paths:
- ".github/workflows/xmake.yml"
- "include/**"
- "src/**"
- "tests/**"
- "xmake.lua"
jobs:
linux:
strategy:
matrix:
os: [ubuntu-24.04]
build_type: [release, debug]
runs-on: ${{ matrix.os }}
steps:
- name: Setup llvm & libstdc++ & cmake & ninja
run: |
sudo apt update
sudo apt install -y gcc-14 g++-14 libstdc++-14-dev
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100
sudo update-alternatives --set gcc /usr/bin/gcc-14
sudo update-alternatives --set g++ /usr/bin/g++-14
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 20 all
sudo apt install -y cmake ninja-build
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: branch@master
actions-cache-folder: ".xmake-cache"
actions-cache-key: ${{ matrix.os }}
package-cache: true
package-cache-key: ${{ matrix.os }}
build-cache: true
build-cache-key: ${{ matrix.os }}-${{ matrix.build_type }}
- name: Xmake configure
run: |
xmake config --yes --mode=${{ matrix.build_type }} --toolchain=clang-20
- name: Build clice
run: |
xmake build --verbose --diagnosis --all
- name: Run tests
run: xmake test --verbose
windows:
strategy:
matrix:
os: [windows-2025]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: branch@master
actions-cache-folder: ".xmake-cache"
actions-cache-key: ${{ matrix.os }}
package-cache: true
package-cache-key: ${{ matrix.os }}
build-cache: true
build-cache-key: ${{ matrix.os }}-${{ matrix.build_type }}
- name: Xmake configure
run: |
xmake config --yes --toolchain=clang
- name: Build clice
run: |
xmake build --verbose --diagnosis --all
- name: Run tests
run: xmake test --verbose
macos:
strategy:
matrix:
os: [macos-15]
build_type: [release, debug]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup llvm
run: |
brew install llvm@20
- name: Setup xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: branch@master
actions-cache-folder: ".xmake-cache"
actions-cache-key: ${{ matrix.os }}
package-cache: true
package-cache-key: ${{ matrix.os }}
build-cache: true
build-cache-key: ${{ matrix.os }}-${{ matrix.build_type }}
- name: Xmake configure
run: |
xmake config --yes --ci=y --mode=${{ matrix.build_type }} --toolchain=clang --sdk=/opt/homebrew/opt/llvm@20
- name: Build clice
run: |
xmake build --verbose --diagnosis --all
- name: Run tests
run: |
# Workaround for MacOS
export PATH="/opt/homebrew/opt/llvm@20/bin:/opt/homebrew/opt/lld@20/bin:$PATH"
xmake test --verbose

43
.gitignore vendored
View File

@@ -16,10 +16,6 @@
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
@@ -31,17 +27,42 @@
*.out
*.app
temp/
# Fortran module files
*.mod
*.smod
# Build & Toolchain
*build*/
temp/
.cache/
.clice/
.llvm*/
.xmake/
.vscode/
.llvm*/
.clice/
compile_commands.json
perf.data
flamegraph.svg
# Nodejs & Web
*.vsix
dist/
out/
cache/
node_modules/
.vscode-test/
# Python & Testing
__pycache__/
.pytest_cache/
tests/unit/Local/
**/node_modules
docs/.vitepress/dist
docs/.vitepress/cache
# IDEs & Editors
/.vscode/
.vs/
.idea/
.claude
.clangd
# pixi environments
.env
.pixi/*
!.pixi/config.toml

View File

@@ -1,6 +0,0 @@
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v20.1.0"
hooks:
- id: clang-format
files: '^(src|include)(/[^/]+)*/[^/]+\.(h|cpp|cc)$'

23
.prettierrc.yaml Normal file
View File

@@ -0,0 +1,23 @@
# .prettierrc.yaml
printWidth: 100
tabWidth: 4
useTabs: false
semi: true
singleQuote: false
jsxSingleQuote: false
quoteProps: "as-needed"
trailingComma: "all"
bracketSpacing: true
arrowParens: "always"
endOfLine: "lf"
overrides:
- files: "*.md"
options:
proseWrap: "preserve"
tabWidth: 2
- files: ["*.json", "*.yaml", "*.yml", ".clang-format", ".clang-tidy"]
options:
tabWidth: 2

View File

@@ -1,145 +1,213 @@
cmake_minimum_required(VERSION 3.20)
cmake_minimum_required(VERSION 3.30)
project(CLICE_PROJECT LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_SCAN_FOR_MODULES OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
# set llvm-libs install path
if(NOT DEFINED LLVM_INSTALL_PATH OR LLVM_INSTALL_PATH STREQUAL "")
message(FATAL_ERROR "Error: The variable LLVM_INSTALL_PATH is not set. Please specify it with -DLLVM_INSTALL_PATH=<value>.")
endif()
get_filename_component(LLVM_INSTALL_PATH "${LLVM_INSTALL_PATH}" ABSOLUTE)
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
if(NOT EXISTS "${LLVM_INSTALL_PATH}")
message(FATAL_ERROR "Error: The specified LLVM_INSTALL_PATH does not exist: ${LLVM_INSTALL_PATH}")
endif()
message(STATUS "Found llvm-libs ${LLVM_INSTALL_PATH}")
option(CLICE_ENABLE_LTO "Enable ThinLTO for all targets" OFF)
set(CMAKE_PREFIX_PATH "${LLVM_INSTALL_PATH}")
# install dependencies
include(FetchContent)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_BUILD_TYPE STREQUAL "Debug")
# libuv option
set(ASAN ON CACHE BOOL "" FORCE)
# Make sure all third libraries are affected by ABI related options
if(CLICE_USE_LIBCXX)
string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -stdlib=libc++")
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -stdlib=libc++")
endif()
FetchContent_Declare(
tomlplusplus
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
)
FetchContent_Declare(
libuv
GIT_REPOSITORY https://github.com/libuv/libuv.git
GIT_TAG v1.x
)
FetchContent_MakeAvailable(tomlplusplus libuv)
if(CLICE_ENABLE_LTO)
string(APPEND CMAKE_C_FLAGS " -flto=thin")
string(APPEND CMAKE_CXX_FLAGS " -flto=thin")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -flto=thin")
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -flto=thin")
string(APPEND CMAKE_MODULE_LINKER_FLAGS " -flto=thin")
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-fsanitize=address)
if(NOT WIN32)
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=address")
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -fsanitize=address")
endif()
if(MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
execute_process(
COMMAND ${CMAKE_CXX_COMPILER} --print-resource-dir
OUTPUT_VARIABLE CLANG_RESOURCE_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(ASAN_LIB_PATH "${CLANG_RESOURCE_DIR}/lib/windows")
link_directories(${ASAN_LIB_PATH})
set(ASAN_LINK_FLAGS "")
list(APPEND ASAN_LINK_FLAGS "clang_rt.asan_dynamic-x86_64.lib")
list(APPEND ASAN_LINK_FLAGS "/wholearchive:clang_rt.asan_dynamic_runtime_thunk-x86_64.lib")
foreach(flag ${ASAN_LINK_FLAGS})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${flag}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${flag}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${flag}")
endforeach()
endif()
endif()
if(APPLE)
# https://conda-forge.org/docs/maintainer/knowledge_base/#newer-c-features-with-old-sdk
string(APPEND CMAKE_CXX_FLAGS " -D_LIBCPP_DISABLE_AVAILABILITY=1")
endif()
include("${PROJECT_SOURCE_DIR}/cmake/package.cmake")
add_library(clice_options INTERFACE)
if(CLICE_ENABLE_TEST)
target_compile_definitions(clice_options INTERFACE CLICE_ENABLE_TEST=1)
endif()
if(CLICE_CI_ENVIRONMENT)
target_compile_definitions(clice_options INTERFACE CLICE_CI_ENVIRONMENT=1)
endif()
if(WIN32)
target_link_libraries(clice_options INTERFACE version ntdll)
endif()
if(WIN32)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
target_link_options(clice_options INTERFACE
-fuse-ld=lld-link
-Wl,/OPT:REF
#,/OPT:NOICF
)
elseif(APPLE)
target_link_options(clice_options INTERFACE
-fuse-ld=lld
-Wl,-dead_strip
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_options(clice_options INTERFACE
-fuse-ld=lld
-static-libstdc++ -static-libgcc
-Wl,--gc-sections
)
endif()
set(CLICE_CXX_FLAGS "-fno-rtti;-fno-exceptions;-Wno-deprecated-declarations;-Wno-undefined-inline;")
set(CLICE_LINKER_FLAGS "")
if(CLICE_USE_LIBCXX)
list(APPEND CLICE_CXX_FLAGS "-stdlib=libc++")
list(APPEND CLICE_LINKER_FLAGS "-stdlib=libc++")
endif()
# Build-type specific flags
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message(STATUS "Debug build: Enabling -g -O0 -fsanitize=address")
list(APPEND CLICE_CXX_FLAGS "-g;-O0;-fsanitize=address")
list(APPEND CLICE_LINKER_FLAGS "-fsanitize=address")
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
message(STATUS "RelWithDebInfo build: Enabling -fsanitize=thread")
list(APPEND CLICE_CXX_FLAGS "-fsanitize=thread")
list(APPEND CLICE_LINKER_FLAGS "-fsanitize=thread")
else()
message(STATUS "Release/Default build: Enabling -O3")
list(APPEND CLICE_CXX_FLAGS "-O3")
endif()
# Linker flags for LLD
if(WIN32)
list(APPEND CLICE_LINKER_FLAGS "-fuse-ld=lld-link")
else()
list(APPEND CLICE_LINKER_FLAGS "-fuse-ld=lld")
endif()
# build clice core part as library
file(GLOB_RECURSE CLICE_SOURCES
"${CMAKE_SOURCE_DIR}/src/AST/*.cpp"
"${CMAKE_SOURCE_DIR}/src/Async/*.cpp"
"${CMAKE_SOURCE_DIR}/src/Basic/*.cpp"
"${CMAKE_SOURCE_DIR}/src/Compiler/*.cpp"
"${CMAKE_SOURCE_DIR}/src/Index/*.cpp"
"${CMAKE_SOURCE_DIR}/src/Feature/*.cpp"
"${CMAKE_SOURCE_DIR}/src/Server/*.cpp"
"${CMAKE_SOURCE_DIR}/src/Support/*.cpp"
)
add_library(clice-core STATIC "${CLICE_SOURCES}")
# set llvm include and lib path
add_library(llvm-libs INTERFACE IMPORTED)
target_include_directories(llvm-libs INTERFACE "${LLVM_INSTALL_PATH}/include")
if(WIN32)
target_compile_definitions(llvm-libs INTERFACE "CLANG_BUILD_STATIC")
target_link_libraries(llvm-libs INTERFACE version ntdll)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_link_directories(llvm-libs INTERFACE "${LLVM_INSTALL_PATH}/lib")
target_link_libraries(llvm-libs INTERFACE
LLVMSupport
LLVMFrontendOpenMP
LLVMOption
clangAST
clangASTMatchers
clangBasic
clangDependencyScanning
clangDriver
clangFormat
clangFrontend
clangIndex
clangLex
clangSema
clangSerialization
clangTooling
clangToolingCore
clangToolingInclusions
clangToolingInclusionsStdlib
clangToolingSyntax
if(MSVC OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND
CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC"))
target_compile_options(clice_options INTERFACE
/GR-
/EHsc-
/Zc:preprocessor
)
else()
file(GLOB LLVM_LIBRARIES CONFIGURE_DEPENDS "${LLVM_INSTALL_PATH}/lib/*${CMAKE_STATIC_LIBRARY_SUFFIX}")
target_link_libraries(llvm-libs INTERFACE ${LLVM_LIBRARIES})
target_compile_options(clice_options INTERFACE
-fno-rtti
-fno-exceptions
-Wno-deprecated-declarations
-Wno-undefined-inline
-ffunction-sections
-fdata-sections
)
endif()
target_compile_options(clice-core PUBLIC ${CLICE_CXX_FLAGS})
target_link_options(clice-core PUBLIC ${CLICE_LINKER_FLAGS})
set(FBS_SCHEMA_FILE "${CMAKE_CURRENT_SOURCE_DIR}/include/Index/schema.fbs")
set(GENERATED_HEADER "${CMAKE_CURRENT_BINARY_DIR}/generated/schema_generated.h")
target_include_directories(clice-core PUBLIC "${CMAKE_SOURCE_DIR}/include")
target_link_libraries(clice-core PUBLIC uv_a tomlplusplus::tomlplusplus llvm-libs)
add_custom_command(
OUTPUT ${GENERATED_HEADER}
COMMAND $<TARGET_FILE:flatc> --cpp -o ${CMAKE_CURRENT_BINARY_DIR}/generated ${FBS_SCHEMA_FILE}
DEPENDS ${FBS_SCHEMA_FILE}
COMMENT "Generating C++ header from ${FBS_SCHEMA_FILE}"
)
# clice executable
add_executable(clice "${CMAKE_SOURCE_DIR}/src/Driver/clice.cc")
add_custom_target(
generate_flatbuffers_schema
DEPENDS ${GENERATED_HEADER}
)
set(CONFIG_SOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/config/clang-tidy-config.h")
set(CONFIG_GENERATED_FILE "${CMAKE_CURRENT_BINARY_DIR}/generated/clang-tidy-config.h")
add_custom_command(
OUTPUT ${CONFIG_GENERATED_FILE}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CONFIG_SOURCE_FILE} ${CONFIG_GENERATED_FILE}
DEPENDS ${CONFIG_SOURCE_FILE}
COMMENT "Generating C++ header from ${CONFIG_SOURCE_FILE}"
)
add_custom_target(
generate_config
DEPENDS ${CONFIG_GENERATED_FILE}
)
add_library(clice_core_deps INTERFACE)
target_include_directories(clice_core_deps INTERFACE
"${PROJECT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_BINARY_DIR}/generated"
)
target_link_libraries(clice_core_deps INTERFACE
clice_options
libuv::libuv
spdlog::spdlog
tomlplusplus::tomlplusplus
roaring::roaring
flatbuffers
llvm-libs
)
add_library(clice_builtin_api INTERFACE)
target_link_libraries(clice_builtin_api INTERFACE clice_core_deps)
include("${PROJECT_SOURCE_DIR}/cmake/builtin-libraries.cmake")
clice_include_builtin_library_modules()
file(GLOB_RECURSE CLICE_SOURCES CONFIGURE_DEPENDS
"${PROJECT_SOURCE_DIR}/src/AST/*.cpp"
"${PROJECT_SOURCE_DIR}/src/Async/*.cpp"
"${PROJECT_SOURCE_DIR}/src/Basic/*.cpp"
"${PROJECT_SOURCE_DIR}/src/Compiler/*.cpp"
"${PROJECT_SOURCE_DIR}/src/Index/*.cpp"
"${PROJECT_SOURCE_DIR}/src/Feature/*.cpp"
"${PROJECT_SOURCE_DIR}/src/Server/*.cpp"
"${PROJECT_SOURCE_DIR}/src/Support/*.cpp"
)
add_library(clice-core STATIC "${CLICE_SOURCES}")
add_dependencies(clice-core generate_flatbuffers_schema generate_config)
target_link_libraries(clice-core PUBLIC clice_core_deps)
clice_finalize_builtin_libraries(TARGET clice-core)
add_executable(clice "${PROJECT_SOURCE_DIR}/src/clice.cc")
target_link_libraries(clice PRIVATE clice-core)
target_compile_options(clice PUBLIC ${CLICE_CXX_FLAGS})
target_link_options(clice PUBLIC ${CLICE_LINKER_FLAGS})
install(TARGETS clice RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
message(STATUS "Copying resource directory for development build")
file(
COPY "${LLVM_INSTALL_PATH}/lib/clang"
DESTINATION "${PROJECT_BINARY_DIR}/lib"
)
install(
DIRECTORY "${LLVM_INSTALL_PATH}/lib/clang"
DESTINATION "${CMAKE_INSTALL_LIBDIR}"
)
# clice tests
if(CLICE_ENABLE_TEST)
file(GLOB_RECURSE CLICE_TEST_SOURCES "${CMAKE_SOURCE_DIR}/tests/unit/*/*.cpp")
add_executable(unit_tests "${CLICE_TEST_SOURCES}" "${CMAKE_SOURCE_DIR}/src/Driver/unit_tests.cc")
target_include_directories(unit_tests PUBLIC "${CMAKE_SOURCE_DIR}")
target_link_libraries(unit_tests PRIVATE clice-core)
target_compile_options(unit_tests PUBLIC ${CLICE_CXX_FLAGS})
target_link_options(unit_tests PUBLIC ${CLICE_LINKER_FLAGS})
add_executable(helper "${CMAKE_SOURCE_DIR}/src/Driver/helper.cc")
target_link_libraries(helper PRIVATE clice-core)
file(GLOB_RECURSE CLICE_TEST_SOURCES CONFIGURE_DEPENDS
"${PROJECT_SOURCE_DIR}/tests/unit/*/*.cpp")
add_executable(unit_tests
"${CLICE_TEST_SOURCES}"
"${PROJECT_SOURCE_DIR}/tests/unit/unit_tests.cc"
)
target_include_directories(unit_tests PUBLIC "${PROJECT_SOURCE_DIR}")
target_link_libraries(unit_tests PRIVATE clice-core cpptrace::cpptrace)
endif()

214
LICENSE
View File

@@ -1,21 +1,201 @@
MIT License
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Copyright (c) 2024 ykiko
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
1. Definitions.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,25 +1,38 @@
# clice: a powerful and efficient language server for c/c++
<!-- Begin section: Overview -->
clice is a new language server for c/c++. It is still in the early stages of development, so just wait for a few months.
# clice
Current progress is recorded in issues, feel free to share your ideas and suggestions!
![C++ Standard](https://img.shields.io/badge/C++-23-blue.svg)
[![GitHub license](https://img.shields.io/github/license/clice-io/clice)](https://github.com/clice-io/clice/blob/main/LICENSE)
[![Actions status](https://github.com/clice-io/clice/workflows/CI/badge.svg)](https://github.com/clice-io/clice/actions)
[![Documentation](https://img.shields.io/badge/view-documentation-blue)](https://clice.io)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/clice-io/clice)
[![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?logo=discord&logoColor=white)](https://discord.gg/PA3UxW2VA3)
# Why write a new language server?
clice is a next-generation language server designed for modern C++. Through excellent asynchronous task scheduling and intelligent caching, it achieves a lower memory footprint and faster response times.
In VSCode, there are mainly three C++ plugins: cpp-tools, ccls, and clangd. Based on my experience, **clangd > ccls > cpptools**. However, this doesn't mean it has no shortcomings. In fact, compared to CLion's clangd (CLion uses its own private clangd branch), clangd has a significant gap.
Beyond performance, clice provides instantiation-aware template processing, supports switching header contexts between different source files (including non-self-contained headers), and offers comprehensive support for C++20 modules, from code completion to go-to-definition. Our goal is to provide C++ developers with a truly fast, precise, and intelligent development companion.
Given this, why not contribute to clangd instead of writing a new one? The main reasons are:
> [!IMPORTANT]
> Support for header contexts and C++20 modules are core features currently under active development. They will be progressively refined in upcoming releases. Stay tuned!
Clangd was initially maintained by several Google employees: [Sam McCall](https://github.com/sam-mccall), [kadircet](https://github.com/kadircet), and [hokein](https://github.com/hokein). They mainly addressed Google's internal needs, and more complex requests from other users often had very low priority. Moreover, starting from 2023, these employees seem to have been reassigned to other projects. Clangd now has only one passionate, voluntary maintainer: [Nathan Ridge](https://github.com/HighCommander4). But he also has his own work to attend to, and his time is very limited—possibly only enough to answer some user queries in issues.
## Getting started
Some complex requirements often require large-scale modifications to clangd, and currently, there's no one available to review the related code. Such PRs might be shelved for a very long time. As far as I know, issues like adding support for C++20 modules to clangd—such as [Introduce initial support for C++20 Modules](https://github.com/llvm/llvm-project/pull/66462) — have been delayed for nearly a year. This pace is unacceptable to me. So the current situation is that making significant changes to clangd and merging them into the mainline is very difficult.
Download the latest `clice` binary from the [releases page](https://github.com/clice-io/clice/releases) and install the [vscode extension](https://marketplace.visualstudio.com/items?itemName=ykiko.clice-vscode). Then, add the following configuration to your `.vscode/settings.json` file:
# Why should you choose clice?
```jsonc
{
// Optional: Set this to an empty string to turn off the clangd.
"clangd.path": "",
- Support non self contained files
- Support more code actions
- Support full C++20 named module
- Support more semantic tokens
- Better response inside template
- Better performance and less memory usage
- Better index format
// Point this to the clice binary you downloaded.
"clice.executable": "/path/to/your/clice/executable",
}
```
> [!NOTE]
> As an early version, please do not use it in a production environment. Crashes are expected, and we welcome you to submit issues.
## Documentation
To learn more about building, installing, and configuring clice, or to dive deep into its features and architecture, please visit our official documentation at [**clice.io**](https://clice.io/).

View File

@@ -0,0 +1,158 @@
include_guard(GLOBAL)
set(
CLICE_BUILTIN_LIBRARY_MODULES
"${CLICE_BUILTIN_LIBRARY_MODULES}"
CACHE STRING
"Semicolon-separated list of CMake modules that register extra builtin clice libraries"
)
function(clice_add_builtin_library)
set(options)
set(oneValueArgs NAME ENTRYPOINT)
set(multiValueArgs SOURCES INCLUDE_DIRECTORIES LINK_LIBRARIES COMPILE_DEFINITIONS COMPILE_OPTIONS)
cmake_parse_arguments(CBL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(CBL_UNPARSED_ARGUMENTS)
message(
FATAL_ERROR
"clice_add_builtin_library got unexpected arguments: ${CBL_UNPARSED_ARGUMENTS}"
)
endif()
if(NOT CBL_NAME)
message(FATAL_ERROR "clice_add_builtin_library requires NAME")
endif()
if(NOT CBL_SOURCES)
message(FATAL_ERROR "clice_add_builtin_library(${CBL_NAME}) requires SOURCES")
endif()
if(NOT CBL_ENTRYPOINT)
message(FATAL_ERROR "clice_add_builtin_library(${CBL_NAME}) requires ENTRYPOINT")
endif()
if(NOT TARGET clice_builtin_api)
message(
FATAL_ERROR
"clice_builtin_api must be defined before calling clice_add_builtin_library(${CBL_NAME})"
)
endif()
set(target "clice_builtin_${CBL_NAME}")
if(TARGET "${target}")
message(FATAL_ERROR "builtin library target '${target}' already exists")
endif()
add_library("${target}" OBJECT)
target_sources("${target}" PRIVATE ${CBL_SOURCES})
target_link_libraries("${target}" PUBLIC clice_builtin_api)
add_dependencies("${target}" generate_flatbuffers_schema generate_config)
if(CBL_INCLUDE_DIRECTORIES)
target_include_directories("${target}" PRIVATE ${CBL_INCLUDE_DIRECTORIES})
endif()
if(CBL_LINK_LIBRARIES)
target_link_libraries("${target}" PUBLIC ${CBL_LINK_LIBRARIES})
endif()
if(CBL_COMPILE_DEFINITIONS)
target_compile_definitions("${target}" PRIVATE ${CBL_COMPILE_DEFINITIONS})
endif()
if(CBL_COMPILE_OPTIONS)
target_compile_options("${target}" PRIVATE ${CBL_COMPILE_OPTIONS})
endif()
set_property(GLOBAL APPEND PROPERTY CLICE_BUILTIN_LIBRARY_TARGETS "${target}")
set_property(GLOBAL APPEND PROPERTY CLICE_BUILTIN_LIBRARY_ENTRYPOINTS "${CBL_ENTRYPOINT}")
endfunction()
function(clice_include_builtin_library_modules)
foreach(module_path IN LISTS CLICE_BUILTIN_LIBRARY_MODULES)
cmake_path(
ABSOLUTE_PATH module_path
BASE_DIRECTORY "${PROJECT_SOURCE_DIR}"
NORMALIZE
OUTPUT_VARIABLE module_abs_path
)
if(NOT EXISTS "${module_abs_path}")
message(
FATAL_ERROR
"builtin library module '${module_path}' does not exist: ${module_abs_path}"
)
endif()
include("${module_abs_path}")
endforeach()
endfunction()
function(clice_finalize_builtin_libraries)
set(options)
set(oneValueArgs TARGET REGISTRATION_SOURCE)
cmake_parse_arguments(CBL "${options}" "${oneValueArgs}" "" ${ARGN})
if(CBL_UNPARSED_ARGUMENTS)
message(
FATAL_ERROR
"clice_finalize_builtin_libraries got unexpected arguments: ${CBL_UNPARSED_ARGUMENTS}"
)
endif()
if(NOT CBL_TARGET)
message(FATAL_ERROR "clice_finalize_builtin_libraries requires TARGET")
endif()
if(NOT TARGET "${CBL_TARGET}")
message(FATAL_ERROR "target '${CBL_TARGET}' does not exist")
endif()
if(NOT CBL_REGISTRATION_SOURCE)
set(CBL_REGISTRATION_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/generated/builtin-libraries.cpp")
endif()
get_property(builtin_targets GLOBAL PROPERTY CLICE_BUILTIN_LIBRARY_TARGETS)
get_property(builtin_entrypoints GLOBAL PROPERTY CLICE_BUILTIN_LIBRARY_ENTRYPOINTS)
if(NOT builtin_targets)
set(builtin_targets "")
endif()
if(NOT builtin_entrypoints)
set(builtin_entrypoints "")
endif()
set(registration_source_content "#include \"Server/Plugin.h\"\n\nnamespace clice {\n\n")
foreach(entrypoint IN LISTS builtin_entrypoints)
string(APPEND registration_source_content "::clice::PluginInfo ${entrypoint}();\n")
endforeach()
string(APPEND registration_source_content "\nvoid register_builtin_server_plugins(ServerPluginBuilder& builder) {\n")
foreach(entrypoint IN LISTS builtin_entrypoints)
string(
APPEND
registration_source_content
" ${entrypoint}().register_server_callbacks(builder);\n"
)
endforeach()
string(APPEND registration_source_content "}\n\n} // namespace clice\n")
get_filename_component(registration_source_dir "${CBL_REGISTRATION_SOURCE}" DIRECTORY)
file(MAKE_DIRECTORY "${registration_source_dir}")
file(CONFIGURE OUTPUT "${CBL_REGISTRATION_SOURCE}" CONTENT "${registration_source_content}" @ONLY)
target_sources("${CBL_TARGET}" PRIVATE "${CBL_REGISTRATION_SOURCE}")
if(builtin_targets)
foreach(builtin_target IN LISTS builtin_targets)
target_sources("${CBL_TARGET}" PRIVATE $<TARGET_OBJECTS:${builtin_target}>)
endforeach()
target_link_libraries("${CBL_TARGET}" PRIVATE ${builtin_targets})
endif()
endfunction()

108
cmake/llvm.cmake Normal file
View File

@@ -0,0 +1,108 @@
include_guard()
function(setup_llvm LLVM_VERSION)
find_package(Python3 COMPONENTS Interpreter REQUIRED)
set(LLVM_SETUP_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/.llvm/setup-llvm.json")
set(LLVM_SETUP_SCRIPT "${PROJECT_SOURCE_DIR}/scripts/setup-llvm.py")
set(LLVM_SETUP_ARGS
"--version" "${LLVM_VERSION}"
"--build-type" "${CMAKE_BUILD_TYPE}"
"--binary-dir" "${CMAKE_CURRENT_BINARY_DIR}"
"--manifest" "${PROJECT_SOURCE_DIR}/config/llvm-manifest.json"
"--output" "${LLVM_SETUP_OUTPUT}"
)
if(CLICE_ENABLE_LTO)
list(APPEND LLVM_SETUP_ARGS "--enable-lto")
endif()
if(DEFINED LLVM_INSTALL_PATH AND NOT LLVM_INSTALL_PATH STREQUAL "")
list(APPEND LLVM_SETUP_ARGS "--install-path" "${LLVM_INSTALL_PATH}")
endif()
if(DEFINED CLICE_OFFLINE_BUILD AND CLICE_OFFLINE_BUILD)
list(APPEND LLVM_SETUP_ARGS "--offline")
endif()
execute_process(
COMMAND "${Python3_EXECUTABLE}" "${LLVM_SETUP_SCRIPT}" ${LLVM_SETUP_ARGS}
RESULT_VARIABLE LLVM_SETUP_RESULT
OUTPUT_VARIABLE LLVM_SETUP_STDOUT
ERROR_VARIABLE LLVM_SETUP_STDERR
ECHO_OUTPUT_VARIABLE
ECHO_ERROR_VARIABLE
COMMAND_ERROR_IS_FATAL ANY
)
file(READ "${LLVM_SETUP_OUTPUT}" LLVM_SETUP_JSON)
string(JSON LLVM_INSTALL_PATH GET "${LLVM_SETUP_JSON}" install_path)
string(JSON LLVM_CMAKE_DIR GET "${LLVM_SETUP_JSON}" cmake_dir)
set(LLVM_INSTALL_PATH "${LLVM_INSTALL_PATH}" CACHE PATH "Path to LLVM installation" FORCE)
set(LLVM_CMAKE_DIR "${LLVM_CMAKE_DIR}" CACHE PATH "Path to LLVM CMake files" FORCE)
get_filename_component(LLVM_INSTALL_PATH "${LLVM_INSTALL_PATH}" ABSOLUTE)
if(NOT EXISTS "${LLVM_INSTALL_PATH}")
message(FATAL_ERROR "Error: The specified LLVM_INSTALL_PATH does not exist: ${LLVM_INSTALL_PATH}")
endif()
# set llvm include and lib path
add_library(llvm-libs INTERFACE IMPORTED)
# add to include directories
target_include_directories(llvm-libs INTERFACE "${LLVM_INSTALL_PATH}/include")
if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT WIN32)
target_link_directories(llvm-libs INTERFACE "${LLVM_INSTALL_PATH}/lib")
target_link_libraries(llvm-libs INTERFACE
LLVMSupport
LLVMFrontendOpenMP
LLVMOption
LLVMTargetParser
clangAST
clangASTMatchers
clangBasic
clangDriver
clangFormat
clangFrontend
clangLex
clangSema
clangSerialization
clangTidy
clangTidyUtils
clangTidyAndroidModule
clangTidyAbseilModule
clangTidyAlteraModule
clangTidyBoostModule
clangTidyBugproneModule
clangTidyCERTModule
clangTidyConcurrencyModule
clangTidyCppCoreGuidelinesModule
clangTidyDarwinModule
clangTidyFuchsiaModule
clangTidyGoogleModule
clangTidyHICPPModule
clangTidyLinuxKernelModule
clangTidyLLVMModule
clangTidyLLVMLibcModule
clangTidyMiscModule
clangTidyModernizeModule
clangTidyObjCModule
clangTidyOpenMPModule
clangTidyPerformanceModule
clangTidyPortabilityModule
clangTidyReadabilityModule
clangTidyZirconModule
clangTooling
clangToolingCore
clangToolingInclusions
clangToolingInclusionsStdlib
clangToolingSyntax
)
else()
file(GLOB LLVM_LIBRARIES CONFIGURE_DEPENDS "${LLVM_INSTALL_PATH}/lib/*${CMAKE_STATIC_LIBRARY_SUFFIX}")
target_link_libraries(llvm-libs INTERFACE ${LLVM_LIBRARIES})
target_compile_definitions(llvm-libs INTERFACE CLANG_BUILD_STATIC=1)
endif()
endfunction()

101
cmake/package.cmake Normal file
View File

@@ -0,0 +1,101 @@
include_guard()
include(${CMAKE_CURRENT_LIST_DIR}/llvm.cmake)
setup_llvm("21.1.4+r1")
# install dependencies
include(FetchContent)
set(FETCHCONTENT_UPDATES_DISCONNECTED ON)
if(WIN32)
set(NULL_DEVICE NUL)
else()
set(NULL_DEVICE /dev/null)
endif()
# libuv
FetchContent_Declare(
libuv
GIT_REPOSITORY https://github.com/libuv/libuv.git
GIT_TAG v1.x
GIT_SHALLOW TRUE
)
if(NOT WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Debug")
set(ASAN ON CACHE BOOL "Enable AddressSanitizer for libuv" FORCE)
endif()
set(LIBUV_BUILD_SHARED OFF CACHE BOOL "" FORCE)
set(LIBUV_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
# spdlog
FetchContent_Declare(
spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.15.3
GIT_SHALLOW TRUE
)
# tomlplusplus
FetchContent_Declare(
tomlplusplus
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
GIT_TAG v3.4.0
GIT_SHALLOW TRUE
)
# croaring
FetchContent_Declare(
croaring
GIT_REPOSITORY https://github.com/RoaringBitmap/CRoaring.git
GIT_TAG v4.4.2
GIT_SHALLOW TRUE
)
set(ENABLE_ROARING_TESTS OFF CACHE INTERNAL "" FORCE)
set(ENABLE_ROARING_MICROBENCHMARKS OFF CACHE INTERNAL "" FORCE)
# flatbuffers
FetchContent_Declare(
flatbuffers
GIT_REPOSITORY https://github.com/google/flatbuffers.git
GIT_TAG v25.9.23
GIT_SHALLOW TRUE
)
set(FLATBUFFERS_BUILD_GRPC OFF CACHE BOOL "" FORCE)
set(FLATBUFFERS_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(FLATBUFFERS_BUILD_FLATHASH OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(libuv spdlog tomlplusplus croaring flatbuffers)
if(CLICE_ENABLE_TEST)
# cpptrace
FetchContent_Declare(
cpptrace
GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git
GIT_TAG v1.0.4
GIT_SHALLOW TRUE
)
set(CPPTRACE_DISABLE_CXX_20_MODULES ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(cpptrace)
endif()
if(WIN32)
target_compile_definitions(uv_a PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
if(NOT MSVC AND TARGET uv_a)
target_compile_options(uv_a PRIVATE
"-Wno-unused-function"
"-Wno-unused-variable"
"-Wno-unused-but-set-variable"
"-Wno-deprecated-declarations"
"-Wno-missing-braces"
)
endif()
target_compile_definitions(spdlog PUBLIC
SPDLOG_USE_STD_FORMAT=1
SPDLOG_NO_EXCEPTIONS=1
)

44
cmake/toolchain.cmake Normal file
View File

@@ -0,0 +1,44 @@
cmake_minimum_required(VERSION 3.30)
if(WIN32)
set(CMAKE_C_COMPILER clang-cl CACHE STRING "C compiler")
set(CMAKE_CXX_COMPILER clang-cl CACHE STRING "C++ compiler")
set(AR_PROGRAM_NAME "llvm-lib")
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL" CACHE STRING "MSVC runtime")
find_program(LLVM_LLD_LINK_PATH "lld-link")
if(LLVM_LLD_LINK_PATH)
set(CMAKE_LINKER "${LLVM_LLD_LINK_PATH}" CACHE FILEPATH "Linker")
endif()
else()
set(CMAKE_C_COMPILER clang CACHE STRING "C compiler")
set(CMAKE_CXX_COMPILER clang++ CACHE STRING "C++ compiler")
set(AR_PROGRAM_NAME "llvm-ar")
set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "Executable linker flags")
set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "Shared library linker flags")
set(CMAKE_MODULE_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "Module linker flags")
endif()
find_program(LLVM_AR_PATH ${AR_PROGRAM_NAME})
if(LLVM_AR_PATH)
set(CMAKE_AR "${LLVM_AR_PATH}" CACHE FILEPATH "Archiver")
set(CMAKE_C_COMPILER_AR "${LLVM_AR_PATH}" CACHE FILEPATH "C archiver")
set(CMAKE_CXX_COMPILER_AR "${LLVM_AR_PATH}" CACHE FILEPATH "C++ archiver")
endif()
find_program(LLVM_RANLIB_PATH "llvm-ranlib")
if(LLVM_RANLIB_PATH)
set(CMAKE_RANLIB "${LLVM_RANLIB_PATH}" CACHE FILEPATH "Ranlib")
set(CMAKE_C_COMPILER_RANLIB "${LLVM_RANLIB_PATH}" CACHE FILEPATH "C ranlib")
set(CMAKE_CXX_COMPILER_RANLIB "${LLVM_RANLIB_PATH}" CACHE FILEPATH "C++ ranlib")
endif()
find_program(LLVM_NM_PATH "llvm-nm")
if(LLVM_NM_PATH)
set(CMAKE_NM "${LLVM_NM_PATH}" CACHE FILEPATH "Symbol lister")
endif()
find_program(LLVM_RC_PATH "llvm-rc")
if(LLVM_RC_PATH)
set(CMAKE_RC_COMPILER "${LLVM_RC_PATH}" CACHE FILEPATH "Resource compiler")
endif()

View File

@@ -0,0 +1,11 @@
/* This generated file is for internal use. Do not include it from headers. */
#ifdef CLANG_TIDY_CONFIG_H
#error clang-tidy-config.h can only be included once
#else
#define CLANG_TIDY_CONFIG_H
// Clice currently doesn't support this configuration, and we use the same default value as clangd.
#define CLANG_TIDY_ENABLE_STATIC_ANALYZER 0
#endif

83
config/llvm-manifest.json Normal file
View File

@@ -0,0 +1,83 @@
[
{
"version": "21.1.4+r1",
"filename": "arm64-macos-clang-debug-asan.tar.xz",
"sha256": "7da4b7d63edefecaf11773e7e701c575140d1a07329bbbb038673b6ee4516ff5",
"lto": false,
"asan": true,
"platform": "macosx",
"build_type": "Debug"
},
{
"version": "21.1.4+r1",
"filename": "arm64-macos-clang-releasedbg-lto.tar.xz",
"sha256": "300455b169448f9f01ae95e3bc269f489558a4ca3955e3032171cc75feca0e30",
"lto": true,
"asan": false,
"platform": "macosx",
"build_type": "RelWithDebInfo"
},
{
"version": "21.1.4+r1",
"filename": "arm64-macos-clang-releasedbg.tar.xz",
"sha256": "9abfc6cd65b957d734ffb97610a634fb4a66d3fbe0fcfb5a1c9124ef693c1495",
"lto": false,
"asan": false,
"platform": "macosx",
"build_type": "RelWithDebInfo"
},
{
"version": "21.1.4+r1",
"filename": "x64-linux-gnu-debug-asan.tar.xz",
"sha256": "c1ad3ec476911596a842ac67dd9c9c9475ce9f0a77b81101d3c801840292e7bc",
"lto": false,
"asan": true,
"platform": "linux",
"build_type": "Debug"
},
{
"version": "21.1.4+r1",
"filename": "x64-linux-gnu-releasedbg-lto.tar.xz",
"sha256": "8a869c2184d139dbba704e2d712e7a68336458ad2d70622b3eb906c3e3511e54",
"lto": true,
"asan": false,
"platform": "linux",
"build_type": "RelWithDebInfo"
},
{
"version": "21.1.4+r1",
"filename": "x64-linux-gnu-releasedbg.tar.xz",
"sha256": "552bab86f715d4f2c027f07eaaf5b3d6b8e430af0b74b470142f3f00da4feec6",
"lto": false,
"asan": false,
"platform": "linux",
"build_type": "RelWithDebInfo"
},
{
"version": "21.1.4+r1",
"filename": "x64-windows-msvc-debug-asan.tar.xz",
"sha256": "093667a493d336c22ff3c604c5f1fea2a7d2c927c1179cec44e9a03726906ac1",
"lto": false,
"asan": true,
"platform": "windows",
"build_type": "Debug"
},
{
"version": "21.1.4+r1",
"filename": "x64-windows-msvc-releasedbg-lto.tar.xz",
"sha256": "010539e85621dc3c6ecf359d899feb4075aeca5d0bba6625cdbec0e570e79129",
"lto": true,
"asan": false,
"platform": "windows",
"build_type": "RelWithDebInfo"
},
{
"version": "21.1.4+r1",
"filename": "x64-windows-msvc-releasedbg.tar.xz",
"sha256": "f473c09fbea10053fac00be409d75dc228d4a38bcbc5e4aeb58b56a4b0dde78e",
"lto": false,
"asan": false,
"platform": "windows",
"build_type": "RelWithDebInfo"
}
]

View File

@@ -1,40 +1,38 @@
import { defineConfig } from 'vitepress'
import { genSidebar } from './theme/sidebar'
import { defineConfig } from "vitepress";
import { genSidebar } from "./theme/sidebar";
// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "clice",
description: "a powerful and modern C++ language server",
base: '/',
rewrites: {
'en/:rest*': ':rest*',
},
locales: {
root: { label: 'English' },
zh: { label: '简体中文' },
},
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
nav: [
{ text: 'Home', link: '/' },
],
sidebar: {
"/zh/": [
genSidebar('zh', 'design', { title: 'Design' }),
genSidebar('zh', 'dev', { title: 'Development' }),
genSidebar('zh', 'guide', { title: 'Guide' }),
],
"/": [
genSidebar('en', 'design', { title: 'Design' }),
genSidebar('en', 'dev', { title: 'Development' }),
genSidebar('en', 'guide', { title: 'Guide' }),
],
title: "clice",
description: "a powerful and modern C++ language server",
cleanUrls: true,
base: "/",
rewrites: {
"en/:rest*": ":rest*",
},
socialLinks: [
{ icon: 'discord', link: 'https://discord.gg/PA3UxW2VA3' },
{ icon: 'github', link: 'https://github.com/clice-project/clice' },
],
outline: 'deep',
}
})
locales: {
root: { label: "English" },
zh: { label: "简体中文" },
},
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
nav: [{ text: "Home", link: "/" }],
sidebar: {
"/zh/": [
genSidebar("zh", "design", { title: "Design" }),
genSidebar("zh", "dev", { title: "Development" }),
genSidebar("zh", "guide", { title: "Guide" }),
],
"/": [
genSidebar("en", "design", { title: "Design" }),
genSidebar("en", "dev", { title: "Development" }),
genSidebar("en", "guide", { title: "Guide" }),
],
},
socialLinks: [
{ icon: "discord", link: "https://discord.gg/PA3UxW2VA3" },
{ icon: "github", link: "https://github.com/clice-io/clice" },
],
outline: "deep",
},
});

View File

@@ -1,17 +1,17 @@
// https://vitepress.dev/guide/custom-theme
import { h } from 'vue'
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import './style.css'
import { h } from "vue";
import type { Theme } from "vitepress";
import DefaultTheme from "vitepress/theme";
import "./style.css";
export default {
extends: DefaultTheme,
Layout: () => {
return h(DefaultTheme.Layout, null, {
// https://vitepress.dev/guide/extending-default-theme#layout-slots
})
},
enhanceApp({ app, router, siteData }) {
// ...
}
} satisfies Theme
extends: DefaultTheme,
Layout: () => {
return h(DefaultTheme.Layout, null, {
// https://vitepress.dev/guide/extending-default-theme#layout-slots
});
},
enhanceApp({ app, router, siteData }) {
// ...
},
} satisfies Theme;

View File

@@ -1,45 +1,45 @@
import fs from 'fs'
import path from 'path'
import { DefaultTheme } from 'vitepress'
import fs from "fs";
import path from "path";
import { DefaultTheme } from "vitepress";
export const genSidebar = (
lang: string,
dirPath: string,
options: {
title: string
collapsible?: boolean
ignore?: string[]
}
title: string;
collapsible?: boolean;
ignore?: string[];
},
): DefaultTheme.SidebarItem => {
const sidebarPath = path.resolve(process.cwd(), lang, dirPath)
const ignore = options.ignore || ['index.md']
const sidebarPath = path.resolve(process.cwd(), lang, dirPath);
const ignore = options.ignore || ["index.md"];
const files = fs
.readdirSync(sidebarPath)
.filter((file) => file.endsWith('.md') && !ignore.includes(file))
.filter((file) => file.endsWith(".md") && !ignore.includes(file));
const items = files.map((file) => {
const content = fs.readFileSync(path.resolve(sidebarPath, file), 'utf-8')
const match = content.match(/^#\s+(.*)/)
const title = match ? match[1] : file.replace('.md', '')
const content = fs.readFileSync(path.resolve(sidebarPath, file), "utf-8");
const match = content.match(/^#\s+(.*)/);
const title = match ? match[1] : file.replace(".md", "");
let prefix = '/';
if (lang != 'en') {
let prefix = "/";
if (lang != "en") {
prefix += lang;
prefix += '/';
prefix += "/";
}
return {
text: title,
/// Make sure link for en is actually root, beacuse Github Pages
/// doesn't support redirect url.
link: `${prefix}${dirPath}/${file.replace('.md', '')}`
}
})
link: `${prefix}${dirPath}/${file.replace(".md", "")}`,
};
});
return {
text: options.title,
collapsed: options.collapsible || false,
items
}
}
items,
};
};

View File

@@ -44,30 +44,30 @@
* -------------------------------------------------------------------------- */
:root {
--vp-c-default-1: var(--vp-c-gray-1);
--vp-c-default-2: var(--vp-c-gray-2);
--vp-c-default-3: var(--vp-c-gray-3);
--vp-c-default-soft: var(--vp-c-gray-soft);
--vp-c-default-1: var(--vp-c-gray-1);
--vp-c-default-2: var(--vp-c-gray-2);
--vp-c-default-3: var(--vp-c-gray-3);
--vp-c-default-soft: var(--vp-c-gray-soft);
--vp-c-brand-1: var(--vp-c-indigo-1);
--vp-c-brand-2: var(--vp-c-indigo-2);
--vp-c-brand-3: var(--vp-c-indigo-3);
--vp-c-brand-soft: var(--vp-c-indigo-soft);
--vp-c-brand-1: var(--vp-c-indigo-1);
--vp-c-brand-2: var(--vp-c-indigo-2);
--vp-c-brand-3: var(--vp-c-indigo-3);
--vp-c-brand-soft: var(--vp-c-indigo-soft);
--vp-c-tip-1: var(--vp-c-brand-1);
--vp-c-tip-2: var(--vp-c-brand-2);
--vp-c-tip-3: var(--vp-c-brand-3);
--vp-c-tip-soft: var(--vp-c-brand-soft);
--vp-c-tip-1: var(--vp-c-brand-1);
--vp-c-tip-2: var(--vp-c-brand-2);
--vp-c-tip-3: var(--vp-c-brand-3);
--vp-c-tip-soft: var(--vp-c-brand-soft);
--vp-c-warning-1: var(--vp-c-yellow-1);
--vp-c-warning-2: var(--vp-c-yellow-2);
--vp-c-warning-3: var(--vp-c-yellow-3);
--vp-c-warning-soft: var(--vp-c-yellow-soft);
--vp-c-warning-1: var(--vp-c-yellow-1);
--vp-c-warning-2: var(--vp-c-yellow-2);
--vp-c-warning-3: var(--vp-c-yellow-3);
--vp-c-warning-soft: var(--vp-c-yellow-soft);
--vp-c-danger-1: var(--vp-c-red-1);
--vp-c-danger-2: var(--vp-c-red-2);
--vp-c-danger-3: var(--vp-c-red-3);
--vp-c-danger-soft: var(--vp-c-red-soft);
--vp-c-danger-1: var(--vp-c-red-1);
--vp-c-danger-2: var(--vp-c-red-2);
--vp-c-danger-3: var(--vp-c-red-3);
--vp-c-danger-soft: var(--vp-c-red-soft);
}
/**
@@ -75,15 +75,15 @@
* -------------------------------------------------------------------------- */
:root {
--vp-button-brand-border: transparent;
--vp-button-brand-text: var(--vp-c-white);
--vp-button-brand-bg: var(--vp-c-brand-3);
--vp-button-brand-hover-border: transparent;
--vp-button-brand-hover-text: var(--vp-c-white);
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
--vp-button-brand-active-border: transparent;
--vp-button-brand-active-text: var(--vp-c-white);
--vp-button-brand-active-bg: var(--vp-c-brand-1);
--vp-button-brand-border: transparent;
--vp-button-brand-text: var(--vp-c-white);
--vp-button-brand-bg: var(--vp-c-brand-3);
--vp-button-brand-hover-border: transparent;
--vp-button-brand-hover-text: var(--vp-c-white);
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
--vp-button-brand-active-border: transparent;
--vp-button-brand-active-text: var(--vp-c-white);
--vp-button-brand-active-bg: var(--vp-c-brand-1);
}
/**
@@ -91,31 +91,23 @@
* -------------------------------------------------------------------------- */
:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(
120deg,
#bd34fe 30%,
#41d1ff
);
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff);
--vp-home-hero-image-background-image: linear-gradient(
-45deg,
#bd34fe 50%,
#47caff 50%
);
--vp-home-hero-image-filter: blur(44px);
--vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
--vp-home-hero-image-filter: blur(44px);
}
@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
:root {
--vp-home-hero-image-filter: blur(56px);
}
}
@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
:root {
--vp-home-hero-image-filter: blur(68px);
}
}
/**
@@ -123,10 +115,10 @@
* -------------------------------------------------------------------------- */
:root {
--vp-custom-block-tip-border: transparent;
--vp-custom-block-tip-text: var(--vp-c-text-1);
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
--vp-custom-block-tip-border: transparent;
--vp-custom-block-tip-text: var(--vp-c-text-1);
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
}
/**
@@ -134,6 +126,5 @@
* -------------------------------------------------------------------------- */
.DocSearch {
--docsearch-primary-color: var(--vp-c-brand-1) !important;
--docsearch-primary-color: var(--vp-c-brand-1) !important;
}

View File

@@ -1,92 +1,47 @@
### clice configuration
## # clice configuration
# This section outlines the supported built-in variables for clice.
# These variables can be referenced in strings using the syntax `${var}`.
# Supported variables:
# - `${version}`: The version of clice.
# - `${binary}`: The path of the clice binary.
# - `${llvm_version}`: The LLVM version used by clice.
# - `${workspace}`: The workspace directory provided by the client.
[server]
# Compile commands directories to search for compile_commands.json files.
compile_commands_dirs = ["${workspace}/build"]
[project]
# Enable experimental clang-tidy diagnostics.
# This feature is tracked in https://github.com/clice-project/clice/issues/90.
clang_tidy = false
# Maximum number of active files to keep in memory. If the number of active files
# exceeds this limit, the least recently used files will be removed.
# The default value is 8. Whatever the number you set, the minimum is 1, the maximum is 512.
max_active_file = 8
# Directory for storing PCH and PCM files.
cache_dir = "${workspace}/.clice/cache"
# Directory for storing index files.
index_dir = "${workspace}/.clice/index"
logging_dir = "${workspace}/.clice/logging"
# Compile commands files or directories to search for compile_commands.json files.
compile_commands_paths = ["${workspace}/build"]
# Maximum number of active files to keep in memory. If the number of active files
# exceeds this limit, the least recently used files will be removed.
# The default value is 8. Whatever the number you set, the minimum is 1, the maximum is 512.
max_active_file = 8
# Cache configuration for storing precompiled headers and modules.
[cache]
# Directory for storing PCH and PCM files.
dir = "${workspace}/.clice/cache"
# Maximum number of cache files to keep. If the total exceeds this limit, clice
# deletes the oldest files automatically. Set to 0 to disable the limit.
limit = 0
# Index configuration for symbol and feature indexing.
[index]
# Directory for storing index files.
dir = "${workspace}/.clice/index"
# Whether to index entities in implicit template instantiations.
implicitInstantiation = true
# Control the behavior for specific files. Note that Clice matches rules
# in order. If you want to add your own rules, either delete this rule
# Control the behavior for specific files. Note that Clice matches rules
# in order. If you want to add your own rules, either delete this rule
# or insert your rule before it.
[[rules]]
# Files matching the specified pattern will have this rule applied.
#
# Patterns can use the following syntax:
# - `*`: Matches one or more characters in a path segment.
# - `?`: Matches a single character in a path segment.
# - `**`: Matches any number of path segments, including none.
# - `{}`: Groups conditions (e.g., `**/*.{ts,js}` matches all TypeScript
# and JavaScript files).
# - `[]`: Declares a range of characters to match in a path segment
# (e.g., `example.[0-9]` matches `example.0`, `example.1`, etc.).
# - `[!...]`: Negates a range of characters to match in a path segment
# (e.g., `example.[!0-9]` matches `example.a`, `example.b`, but not `example.0`).
pattern = "**/*"
# Commands to append to the original command list (e.g., ["-std=c++17"]).
append = []
# Commands to remove from the original command list.
remove = []
# Controls whether the file is treated as readonly.
# Possible values: ["auto", "always", "never"]
#
# - "auto": Treats the file as readonly until you edit it.
# - "always": Always treats the file as readonly.
# - "never": Always treats the file as non-readonly.
#
# Readonly means the file is not editable, and LSP requests such as
# code actions or completions will not be sent to the server. This avoids
# dynamic computation and allows pre-indexed results to be loaded directly,
# improving performance.
readonly = "auto"
# Controls how header files are treated.
# Possible values: ["auto", "always", "never"]
#
# - "auto": Attempts to infer the header context first. If no header context
# is found, the file will be treated as a normal source file.
# - "always": Always treats the file as a header file. If no header context
# is found, errors will be reported.
# - "never": Always treats the file as a source file.
#
# Header context refers to the related source files or additional metadata
# linked to the header file.
header = "auto"
# Specifies extra header contexts (file paths) for the file.
# Normally, header contexts are inferred automatically once the file is indexed.
# However, if you need immediate context before indexing completes, you can
# provide it manually using this field.
contexts = []
# Files matching the specified pattern will have this rule applied.
#
# Patterns can use the following syntax:
# - `*`: Matches one or more characters in a path segment.
# - `?`: Matches a single character in a path segment.
# - `**`: Matches any number of path segments, including none.
# - `{}`: Groups conditions (e.g., `**/*.{ts,js}` matches all TypeScript
# and JavaScript files).
# - `[]`: Declares a range of characters to match in a path segment
# (e.g., `example.[0-9]` matches `example.0`, `example.1`, etc.).
# - `[!...]`: Negates a range of characters to match in a path segment
# (e.g., `example.[!0-9]` matches `example.a`, `example.b`, but not `example.0`).
patterns = ["**/*"]
# Commands to append to the original command list (e.g., ["-std=c++17"]).
append = []
# Commands to remove from the original command list.
remove = []

View File

@@ -28,7 +28,7 @@ A more extreme case is non-self-contained header files, for example:
```cpp
// a.h
struct Y {
struct Y {
X x;
};

View File

@@ -1,131 +1,103 @@
# Build from Source
## Supported Platforms
clice depends on C++23 features and requires a modern C++ toolchain. We also need to link against LLVM/Clang to parse ASTs. To speed up builds, the default configuration downloads our published [clice-llvm](https://github.com/clice-io/clice-llvm) prebuilt package. This assumes your local environment matches the prebuilt environment closely (especially when enabling Address Sanitizer or LTO).
- Windows
- Linux
- MacOS
To simplify setup and keep builds reproducible, we **strongly recommend** [pixi](https://pixi.prefix.dev/latest) to manage the development environment. Dependency versions are pinned in `pixi.toml`.
## Prerequisites
If you prefer not to use pixi, see [Manual Build](#manual-build) below.
This section introduces the prerequisites for compiling clice.
## Quick Start
### Toolchain
Install pixi following the [official guide](https://pixi.prefix.dev/latest/installation).
- clang >= 19
- c++23 compatible standard library
- MSVC STL >= 19.44(VS 2022 17.4)
- GCC libstdc++ >= 14
- Clang libc++ >= 20
clice uses C++23 as the language standard. Please ensure you have an available clang 19 or above compiler, as well as a standard library compatible with C++23.
We ship several tasks; the commands below configure, build, and run tests:
> clice can currently only be compiled with clang. In the future, we will improve this to allow compilation with gcc and msvc.
```shell
# configure && build (default RelWithDebInfo)
pixi run build
### LLVM Libs
- 20.1.5 <= llvm libs < 21
Due to the complexity of C++ syntax, writing a new parser from scratch is unrealistic. clice calls clang's API to parse C++ source files and obtain AST, which means it needs to link llvm/clang libs. Additionally, since clice uses clang's private headers, these private headers are not available in llvm's binary release, so you cannot directly use the system's llvm package.
If you can find the llvm commit corresponding to your system's llvm package, copy the following three files from that commit:
- `clang/lib/Sema/CoroutineStmtBuilder.h`
- `clang/lib/Sema/TypeLocBuilder.h`
- `clang/lib/Sema/TreeTransform.h`
Copy them to `LLVM_INSTALL_PATH/include/clang/Sema/`.
Besides this method, there are two other ways to obtain the llvm libs required by clice:
1. Use our precompiled version
```bash
# .github/workflows/cmake.yml
# Linux precompiled binary require glibc 2.35 (build on ubuntu 22.04)
$ mkdir -p ./.llvm
$ curl -L "https://github.com/clice-project/llvm-binary/releases/download/20.1.5/x86_64-linux-gnu-release.tar.xz" | tar -xJ -C ./.llvm
# MacOS precompiled binary require macos15+
$ mkdir -p ./.llvm
$ curl -L "https://github.com/clice-project/llvm-binary/releases/download/20.1.5/arm64-macosx-apple-release.tar.xz" | tar -xJ -C ./.llvm
# Windows precompiled binary only MD runtime support
$ curl -O -L "https://github.com/clice-project/llvm-binary/releases/download/20.1.5/x64-windows-msvc-release.7z"
$ 7z x x64-windows-msvc-release.7z "-o.llvm"
# unit && integration
pixi run test
```
> [!IMPORTANT]
>
> For debug versions of llvm libs, we enabled address sanitizer during build, and address sanitizer depends on compiler rt, which is very sensitive to compiler versions. So if using debug versions, please ensure your clang's compiler rt version is **strictly consistent** with what we used during build.
>
> - Windows currently has no debug build of llvm libs because it doesn't support building clang as a dynamic library. Related progress can be found [here](https://discourse.llvm.org/t/llvm-is-buildable-as-a-windows-dll/87748)
> - Linux uses clang20
> - MacOS uses homebrew llvm@20, definitely don't use apple clang
For finer-grained tasks (first argument sets the build type):
2. Compile llvm/clang from scratch
This is the most recommended approach, ensuring environment consistency and avoiding crash issues caused by ABI inconsistencies. We provide a script for building the llvm libs required by clice: [build-llvm-libs.py](https://github.com/clice-project/clice/blob/main/scripts/build-llvm-libs.py).
```bash
$ cd llvm-project
$ python3 <clice>/scripts/build-llvm-libs.py debug
```shell
pixi run cmake-config Debug
pixi run cmake-build Debug
pixi run unit-test Debug
pixi run integration-test Debug
```
You can also refer to llvm's official build tutorial [Building LLVM with CMake](https://llvm.org/docs/CMake.html).
> [!TIP]
> If you want to develop directly with `cmake`, `ninja`, `clang++`, etc., run `pixi shell` to enter a shell with all env vars configured.
## Building
### XMake
After handling the prerequisites, you can start building clice. We provide two build methods: cmake/xmake.
We also support building with XMake:
```shell
# config & build (default releasedbg)
pixi run xmake
# unit & integration
pixi run xmake-test
```
## Manual Build
If you plan to build manually, first ensure your toolchain matches the versions defined in `pixi.toml`.
> Compatibility: In theory clice does not rely on compiler-specific extensions, so mainstream compilers (GCC/Clang/MSVC) should work. However, CI only guarantees specific versions of Clang. Other compilers or versions are supported on a **best-effort** basis. Please open an issue or PR if you hit problems.
### CMake
Below are the cmake parameters supported by clice:
- `LLVM_INSTALL_PATH` specifies the installation path of llvm libs
- `CLICE_ENABLE_TEST` whether to build clice's unit tests
For example:
```bash
$ cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DLLVM_INSTALL_PATH="./.llvm" -DCLICE_ENABLE_TEST=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
$ cmake --build build
```
### Xmake
Use the following command to build clice:
```bash
$ xmake f -c --dev=true --mode=debug --toolchain=clang --llvm="./.llvm" --enable_test=true
$ xmake build --all
```
> --llvm is optional. If not specified, xmake will automatically download our precompiled binary
## Run Tests
clice has two forms of tests: unit tests and integration tests.
- Run unit tests:
```bash
$ ./build/bin/unit_tests --test-dir="./tests/data" --resource-dir="<LLVM_INSTALL_PATH>/lib/clang/20"
```
- Run integration tests:
```bash
$ pytest -s --log-cli-level=INFO tests/integration --executable=./build/bin/clice --resource-dir="<LLVM_INSTALL_PATH>/lib/clang/20"
```
> resource-dir is clang's built-in header file folder
Or, if you use xmake as the build system, you can directly run tests through xmake:
```shell
$ xmake test --verbose
$ xmake run unit_tests --verbose
$ xmake test integration_tests/default --verbose
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain.cmake \
-DCLICE_ENABLE_TEST=ON
```
> Note: `CMAKE_TOOLCHAIN_FILE` is optional. If your toolchain exactly matches ours, you can use the predefined `cmake/toolchain.cmake`; otherwise remove that flag.
Optional build options:
| Option | Default | Effect |
| -------------------- | ------- | --------------------------------------------------------------------------------------------------------- |
| LLVM_INSTALL_PATH | "" | Build clice with LLVM from a custom path |
| CLICE_ENABLE_TEST | OFF | Build clice unit tests |
| CLICE_USE_LIBCXX | OFF | Build clice with libc++ (adds `-std=libc++`); if enabled, ensure the LLVM libs are also built with libc++ |
| CLICE_CI_ENVIRONMENT | OFF | Enable the `CLICE_CI_ENVIRONMENT` macro; some tests only run in CI |
| CLICE_BUILTIN_LIBRARY_MODULES | "" | Semicolon-separated list of CMake modules that register builtin libraries compiled into `clice`; see [Builtin Libraries](./builtin-library.md) |
### XMake
Build clice with:
```bash
xmake f -c --mode=releasedbg --toolchain=clang
xmake build --all
```
Optional build options:
| Option | Default | Effect |
| ------------- | ------- | ---------------------------------------- |
| --llvm | "" | Build clice with LLVM from a custom path |
| --enable_test | false | Build clice unit tests |
| --ci | false | Enable `CLICE_CI_ENVIRONMENT` |
## About LLVM
clice calls Clang APIs to parse C++ code, so it must link against LLVM/Clang. Because clice uses Clang's private headers (usually absent from distro packages), the system LLVM package cannot be used directly.
Two ways to satisfy this dependency:
1. We publish prebuilt binaries of the LLVM version we use at [clice-llvm](https://github.com/clice-io/clice-llvm/releases) for CI and release builds. During builds, cmake and xmake download these LLVM libs by default.
> [!IMPORTANT]
>
> For debug LLVM builds, we enable address sanitizer, which depends on compiler-rt and is very sensitive to compiler version. If you use a debug build, ensure your clang compiler-rt version matches the one defined in `pixi.toml`.
2. Build LLVM/Clang yourself to match your environment. If the default prebuilt binaries fail due to ABI or library version mismatches, or you need a custom debug build, use this approach. We provide `scripts/build-llvm.py` to build the required LLVM libs, or refer to LLVM's official guide [Building LLVM with CMake](https://llvm.org/docs/CMake.html).

View File

@@ -0,0 +1,101 @@
# Builtin Libraries
Builtin libraries are compiled directly into the `clice` binary instead of being loaded later with `--plugin-path`.
This is useful when:
- your plugin sources live outside the `clice` source tree
- you want the builtin to be part of the default executable
- you need extra include directories, compile definitions, or link dependencies during the main build
## CMake Entry Point
`clice` now exposes a small helper module at [cmake/builtin-libraries.cmake](/cmake/builtin-libraries.cmake).
Extra builtin libraries are registered through the cache variable `CLICE_BUILTIN_LIBRARY_MODULES`.
Each value in `CLICE_BUILTIN_LIBRARY_MODULES` must be a CMake file. During configure, `clice` includes those files, and each file calls `clice_add_builtin_library(...)`.
## Minimal Module
Create a CMake file in your external project, for example `/path/to/my-plugin/clice-builtin.cmake`:
```cmake
clice_add_builtin_library(
NAME my_plugin
SOURCES
"${CMAKE_CURRENT_LIST_DIR}/src/MyPlugin.cpp"
INCLUDE_DIRECTORIES
"${CMAKE_CURRENT_LIST_DIR}/include"
ENTRYPOINT
clice_get_my_plugin_server_plugin_info
)
```
Then configure `clice` with:
```shell
cmake -B build -G Ninja \
-DCLICE_BUILTIN_LIBRARY_MODULES="/path/to/my-plugin/clice-builtin.cmake"
```
To load multiple modules, pass a semicolon-separated CMake list:
```shell
cmake -B build -G Ninja \
-DCLICE_BUILTIN_LIBRARY_MODULES="/path/to/a.cmake;/path/to/b.cmake"
```
## `clice_add_builtin_library`
The helper accepts the following arguments:
| Argument | Required | Description |
| --- | --- | --- |
| `NAME` | Yes | Logical name used to create an internal object target |
| `SOURCES` | Yes | Source files compiled into `clice`; absolute paths and out-of-tree paths are supported |
| `ENTRYPOINT` | Yes | Unique function name in namespace `clice` that returns `::clice::PluginInfo` |
| `INCLUDE_DIRECTORIES` | No | Extra include directories for this builtin only |
| `LINK_LIBRARIES` | No | Extra libraries or targets needed by this builtin |
| `COMPILE_DEFINITIONS` | No | Extra compile definitions for this builtin |
| `COMPILE_OPTIONS` | No | Extra compile options for this builtin |
## Entrypoint Requirements
Builtin libraries share a single final executable, so each builtin must use its own unique entrypoint function inside namespace `clice`.
Dynamic plugins use:
```cpp
clice_get_server_plugin_info()
```
Builtin libraries should use a unique name such as:
```cpp
clice_get_my_plugin_server_plugin_info()
```
For example:
```cpp
#include "Server/Plugin.h"
namespace clice {
::clice::PluginInfo clice_get_my_plugin_server_plugin_info() {
return {
CLICE_PLUGIN_API_VERSION,
"MyPlugin",
"v0.0.1",
CLICE_PLUGIN_DEF_HASH,
[](clice::ServerPluginBuilder& builder) {
// register callbacks here
},
};
}
} // namespace clice
```
`clice` generates the static registration glue automatically, so once the module is included, no additional edits to `src/clice.cc` are required.

View File

@@ -2,10 +2,11 @@
We welcome any contributions!
Please refer to [build](./build.md) to build clice.
Please refer to [build](./build.md) to build clice, refer to [test and debug](./test-and-debug.md) to test and debug clice.
## Code Style
Naming:
- Variable names: lowercase with underscores
- Class names, enum names: PascalCase

70
docs/en/dev/extension.md Normal file
View File

@@ -0,0 +1,70 @@
# Extension
This section covers development and release workflows for the editor extensions (VSCode / Neovim / Zed).
## VSCode
The VSCode extension uses the Node/PNPM/VSCE toolchain. Work inside the pixi `node` environment for consistent versions.
```shell
# prepare environment (install pixi first)
pixi shell -e node
# install deps (uses pnpm-lock)
pixi run install-vscode
# package the extension; outputs editors/vscode/*.vsix
pixi run build-vscode
```
Publish to the VSCode Marketplace (`VSCE_PAT` env var required):
```shell
pixi run publish-vscode
```
> [!TIP]
> If clice is already built locally, set `clice.executable` in VSCode settings to point the extension to your custom binary.
Develop and debug:
1. `pixi shell -e node`
2. In `editors/vscode`, run `pnpm run watch` for incremental builds
3. In VSCode, use the “Run Extension/Launch Extension” configs, or run `code --extensionDevelopmentPath=$(pwd)/editors/vscode`
Common scripts (inside `pixi shell -e node`):
```bash
pnpm run package # same as pixi run build-vscode
pnpm run publish # same as pixi run publish-vscode
```
If you skip pixi, install node.js >= 20 and pnpm yourself, then in `editors/vscode` run:
```bash
pnpm install
pnpm run package
```
## Neovim
The Neovim extension lives in `editors/nvim` and is written in Lua. It is still evolving.
- Add the repo path to `runtimepath`, e.g. `set rtp+=/path/to/clice/editors/nvim`
- Or create a local symlink: `~/.config/nvim/pack/clice/start/clice` -> `<repo>/editors/nvim`
- Ensure the `clice` executable is discoverable in `$PATH`
Dev tips: the codebase is small—load it directly in Neovim and watch `:messages`/LSP logs; format with `stylua` (config included).
## Zed
The Zed extension lives in `editors/zed` and uses Rust plus `zed_extension_api`.
Suggested local verification:
```bash
cd editors/zed
cargo build --release
```
Then load the local extension per Zed's official guide (Zed CLI required). Make sure `clice` is on `PATH` before launching. Follow the Zed extension publishing flow when releasing.

View File

@@ -0,0 +1,78 @@
You can implement a clice server plugin to extend clice's functionality.
## Use case
When you use `clice` as LSP backend of LLM agents, e.g. claude code, you can add plugin to provide some extra features.
## Writing a plugin
When a plugin is loaded by the server, it will call `clice_get_server_plugin_info` to obtain information about this plugin and about how to register its customization points.
This function needs to be implemented by the plugin, see the example below:
```c++
extern "C" ::clice::PluginInfo LLVM_ATTRIBUTE_WEAK
clice_get_server_plugin_info() {
return {
CLICE_PLUGIN_API_VERSION, "MyPlugin", "v0.1", CLICE_PLUGIN_DEF_HASH,
[](ServerPluginBuilder builder) { ... }
};
}
```
See [PluginProtocol.h](/include/Server/PluginProtocol.h) for more details.
## Compiling a plugin
The plugin must be compiled with the same dependencies and compiler options as clice, otherwise it will cause undefined behavior. [config/llvm-manifest.json](/config/llvm-manifest.json) defines the build information used by clice.
## Loading plugins
For security reasons, clice does not allow loading plugins through configuration files, but must specify the plugin path through command line options.
When `clice` starts, it will load all plugins specified in the command line. You can specify the plugin path through the `--plugin-path` option.
```shell
$ clice --plugin-path /path/to/my-plugin.so
```
## Getting content of `CLICE_PLUGIN_DEF_HASH`
There are two values to return in the `clice_get_server_plugin_info` function.
- `CLICE_PLUGIN_API_VERSION` is used to ensure compability of the `clice_get_server_plugin_info` function between the plugin and the server.
- `CLICE_PLUGIN_DEF_HASH` is used to ensure the consistency of the C++ declarations between the plugin and the server.
To debug the content of `CLICE_PLUGIN_DEF_HASH`, you can run following command:
```shell
$ git clone https://github.com/clice-io/clice.git
$ cd clice
$ git checkout `clice --version --git-describe`
$ python scripts/plugin-def.py content
```
You will get a C source code file, content of which is like this:
```cpp
#if 0
// begin of config/llvm-manifest.json
[
{
"version": "21.1.4+r1",
"filename": "arm64-macos-clang-debug-asan.tar.xz",
"sha256": "7da4b7d63edefecaf11773e7e701c575140d1a07329bbbb038673b6ee4516ff5",
"lto": false,
"asan": true,
"platform": "macosx",
"build_type": "Debug"
},
...
]
...
#endif
```
## Builtin libraries
If you want to compile a plugin directly into the `clice` binary instead of loading it dynamically, see [Builtin Libraries](./builtin-library.md).

View File

@@ -0,0 +1,84 @@
# Test and Debug
## Run Tests
clice has two types of tests: unit tests and integration tests.
- Run unit tests
```bash
$ ./build/bin/unit_tests --test-dir="./tests/data"
```
- Run integration tests
We use pytest to run integration tests. Please refer to `pyproject.toml` to install the required Python libraries.
```bash
$ pytest -s --log-cli-level=INFO tests/integration --executable=./build/bin/clice
```
If you use xmake as your build system, you can run the tests directly with xmake:
```shell
$ xmake run --verbose unit_tests
$ xmake test --verbose integration_tests/default
```
## Debug
If you want to attach a debugger to clice for debugging, it is recommended to first start clice in socket mode independently, and then connect the client to it.
```shell
$ ./build/bin/clice --mode=socket --port=50051
```
After the server starts, you can connect a client to the server in the following two ways:
- Connect by running a specific test with pytest
You can run a single integration test case to connect to a running clice instance. This is very useful for reproducing and debugging specific scenarios.
```shell
$ pytest -s --log-cli-level=INFO tests/integration/test_file_operation.py::test_did_open --mode=socket --port=50051
```
- Use VS Code for practical testing
You can also connect to a running clice service by configuring the clice-vscode extension, allowing you to debug in a real-world usage scenario.
1. Download the [clice-vscode](https://marketplace.visualstudio.com/items?itemName=ykiko.clice-vscode) extension from the Marketplace.
2. Configure `settings.json`: Create a `.vscode/settings.json` file in your project's root directory and add the following content:
```jsonc
{
// Point this to the clice binary you downloaded.
"clice.executable": "/path/to/your/clice/executable",
// Enable socket mode.
"clice.mode": "socket",
"clice.port": 50051,
// Optional: Set this to an empty string to turn off the clangd.
"clangd.path": "",
}
```
3. Reload Window: After modifying the configuration, execute the `Developer: Reload Window` command in VS Code for the settings to take effect. The extension will automatically connect to the clice instance listening on port 50051.
If you need to modify or debug the clice-vscode extension itself, follow these steps:
1. Clone and install dependencies:
```shell
$ git clone https://github.com/clice-io/clice-vscode
$ cd clice-vscode
$ npm install
```
2. Open the extension project with VS Code: Open the `clice-vscode` folder in a new VS Code window.
3. Create debug configuration: In the `clice-vscode` project, also create a `.vscode/settings.json` file with the same content as above.
4. Press `F5`. This will launch an [Extension Development Host] window. This is a new VS Code window with your local clice-vscode extension code loaded. Open your C++ project in this new window, and it should automatically connect to clice.

View File

@@ -2,7 +2,21 @@
This is the documentation for `clice.toml`.
## Server
## Project
| Name | Type | Default |
| ------------------- | -------- | ----------------------------- |
| `project.cache_dir` | `string` | `"${workspace}/.clice/cache"` |
Folder for storing PCH and PCM caches.
<br>
| Name | Type | Default |
| ------------------- | -------- | ----------------------------- |
| `project.index_dir` | `string` | `"${workspace}/.clice/index"` |
Folder for storing index files.
<br>
## Rule
@@ -11,7 +25,7 @@ This is the documentation for `clice.toml`.
| Name | Type |
| ------------------ | ------------------- |
| `[rules].pattern` | `array` of `string` |
| `[rules].patterns` | `array` of `string` |
Glob patterns for matching file paths, following LSP's [standard](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentFilter).
@@ -21,72 +35,18 @@ Glob patterns for matching file paths, following LSP's [standard](https://micros
- `{}`: Used for grouping conditions (e.g., `**/*.{ts,js}` matches all TypeScript and JavaScript files).
- `[]`: Declares a character range to match in a path segment (e.g., `example.[0-9]` matches `example.0`, `example.1`, etc.).
- `[!...]`: Excludes a character range to match in a path segment (e.g., `example.[!0-9]` matches `example.a`, `example.b`, but not `example.0`).
<br>
<br>
| Name | Type | Default |
| ----------------- | ------------------- | ------- |
| `[rules].append` | `array` of `string` | `[]` |
| Name | Type | Default |
| ---------------- | ------------------- | ------- |
| `[rules].append` | `array` of `string` | `[]` |
Commands to append to the original command list. For example, `append = ["-std=c++17"]`.
<br>
| Name | Type | Default |
| ----------------- | ------------------- | ------- |
| `[rules].remove` | `array` of `string` | `[]` |
| Name | Type | Default |
| ---------------- | ------------------- | ------- |
| `[rules].remove` | `array` of `string` | `[]` |
Commands to remove from the original command list. For example, `remove = ["-std=c++11"]`.
<br>
| Name | Type | Default |
| ------------------- | -------- | ------- |
| `[rules].readonly` | `string` | `"auto"` |
Controls whether the file is treated as read-only. Values can be one of `"auto"`, `"always"`, and `"never"`.
- `"auto"`: The file is treated as read-only before you edit it.
- `"always"`: Always treat the file as read-only.
- `"never"`: Always treat the file as non-read-only.
Read-only means the file is not editable, and LSP requests like code actions or completions won't be triggered on it. This avoids dynamic computation and allows direct loading of pre-indexed results, improving performance.
<br>
| Name | Type | Default |
| ----------------- | -------- | ------- |
| `[rules].header` | `string` | `"auto"` |
Controls how to handle header files. Values can be one of `"auto"`, `"always"`, and `"never"`.
- `"auto"`: First try to infer header file context. If no header file context is found, the file will be treated as a regular source file.
- `"always"`: Always treat the file as a header file. If no header file context is found, an error will be reported.
- `"never"`: Always treat the file as a source file.
Header file context refers to the source files or other metadata associated with that header file.
<br>
| Name | Type | Default |
| -------------------- | ------------------- | ------- |
| `[rules].contexts` | `array` of `string` | `[]` |
Specify additional header file contexts (file paths) for the file.
Usually, once a file is indexed, header file context is automatically inferred. However, if you need immediate context before indexing is complete, you can manually provide it using this field.
## Cache
| Name | Type | Default |
| ----------- | -------- | ------------------------------ |
| `cache.dir` | `string` | `"${workspace}/.clice/cache"` |
Folder for storing PCH and PCM caches.
<br>
## Index
| Name | Type | Default |
| ----------- | -------- | ------------------------------ |
| `index.dir` | `string` | `"${workspace}/.clice/index"` |
Folder for storing index files.
<br>
## Feature

View File

@@ -46,7 +46,11 @@ Note: This option only works when cmake's generator is set to makefile and ninja
### Bazel
TODO:
Bazel has no native support to generate a compilation database. The recommended solution is to use [bazel-compile-commands-extractor](https://github.com/hedronvision/bazel-compile-commands-extractor). After setting it up, you can generate `compile_commands.json` with:
```bash
bazel run @hedron_compile_commands//:refresh_all
```
### Visual Studio

View File

@@ -16,8 +16,8 @@ hero:
text: Contribution
link: /dev/contribution
image:
src: /image.png
alt: clice
src: /image.png
alt: clice
features:
- icon: T
@@ -32,4 +32,4 @@ features:
- icon: I
title: Better Performance
details: Excellent asynchronous task scheduling, support for compilation task cancellation, caching necessary information, avoiding meaningless CPU waste
---
---

1795
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,22 @@
{
"name": "docs",
"private": true,
"type": "module",
"devDependencies": {
"@types/node": "^24.1.0",
"vitepress": "^1.6.3"
"@types/node": "^24.10.4",
"vitepress": "^1.6.4"
},
"scripts": {
"docs:dev": "vitepress dev",
"docs:build": "vitepress build",
"docs:preview": "vitepress preview"
},
"pnpm": {
"overrides": {
"esbuild": "~0.25.0"
},
"ignoredBuiltDependencies": [
"esbuild"
]
}
}

1629
docs/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -58,4 +58,5 @@ struct Widget {
template <typename T>
Widget(T) -> Widget<typename T::value_type>;
} // namespace foo

View File

@@ -26,4 +26,4 @@ clice 是一个语言服务器,首先是一个服务器。它使用 [libuv](ht
## Support
一些其它的工具库。
一些其它的工具库。

View File

@@ -16,7 +16,4 @@ int main () {
`iostream` 这个头文件大概有 2w 行代码clice 会先把 `#include <iostream>` 这一行代码构建成 PCH 文件,在完成之后在使用这个 PCH 文件来解析后面的代码。这样的话后续重新解析的代码量就只剩 5 行了,而不是原本的 2w 行,速度会变得非常快。除非你修改了 preamble 部分的代码,导致需要构建新的 preamble。
## Cancel Compilation

View File

@@ -28,7 +28,7 @@ struct Y { ... };
```cpp
// a.h
struct Y {
struct Y {
X x;
};
@@ -39,4 +39,4 @@ struct X {};
`a.h`自身不能被编译,但是嵌入到`b.cpp`中的时候就编译正常了。这种情况下 clangd 会在`a.h`中报错,找不到`X`的定义。显然这是因为它把`a.h`当成一个独立的源文件了。在 libstdc++ 中的代码中就有很多这样的头文件,现在流行的一些 C++ 的 header-only 的库也有些有这样的代码clangd 目前无法处理它们。
clice 将会支持**头文件上下文 (header context)**,支持自动和用户主动切换头文件的状态,当然也会支持非自包含的头文件。我们想要实现如下的效果,以最开始那份代码为例。当你从`b.cpp`跳转到`a.h`的时候使用`b.cpp`作为`a.h`的上下文。同理,当你从`c.cpp`跳转到`a.h`的时候则使用`c.cpp`作为`a.h`的上下文。
clice 将会支持**头文件上下文 (header context)**,支持自动和用户主动切换头文件的状态,当然也会支持非自包含的头文件。我们想要实现如下的效果,以最开始那份代码为例。当你从`b.cpp`跳转到`a.h`的时候使用`b.cpp`作为`a.h`的上下文。同理,当你从`c.cpp`跳转到`a.h`的时候则使用`c.cpp`作为`a.h`的上下文。

View File

@@ -1,2 +1 @@
# Index

View File

@@ -28,5 +28,4 @@ void foo(std::vector<std::vector<T>> vec2) {
2. 它只进行名称查找而不进行模板实例化,就算找到了最后的结果,也没法把它和最初的模板参数映射起来
3. 不考虑默认模板参数,无法处理由默认模板参数导致的依赖名
尽管我们可以对标准库的类型开洞来提供相关的支持但是我希望用户的代码能和标准库的代码有相同的地位那么我们就需要一种通用的算法来处理依赖类型。为了解决这个问题我编写了一个伪实例化器pseudo instantiator。它能在没有具体类型的前提下对依赖类型进行实例化从而达到化简的目的。比如上面这个例子里面的`std::vector<std::vector<T>>::reference`就能被化简为`std::vector<T>&`,进一步就能为用户提供代码补全选项。
尽管我们可以对标准库的类型开洞来提供相关的支持但是我希望用户的代码能和标准库的代码有相同的地位那么我们就需要一种通用的算法来处理依赖类型。为了解决这个问题我编写了一个伪实例化器pseudo instantiator。它能在没有具体类型的前提下对依赖类型进行实例化从而达到化简的目的。比如上面这个例子里面的`std::vector<std::vector<T>>::reference`就能被化简为`std::vector<T>&`,进一步就能为用户提供代码补全选项。

View File

@@ -1,132 +1,103 @@
# Build from Source
## Supported Platforms
clice 依赖 C++23 特性,需要使用高版本的 C++ 编译器。同时,我们需要链接 LLVM/Clang 库来解析 AST。为了加快构建速度默认配置会下载我们发布的 [clice-llvm](https://github.com/clice-io/clice-llvm) 预编译包。这要求你的本地环境与预编译环境保持较高的一致性(尤其是开启 Address Sanitizer 或 LTO 时)。
- Windows
- Linux
- MacOS
为了简化环境设置并保证可复现性,我们**强烈推荐**使用 [pixi](https://pixi.prefix.dev/latest) 来管理开发环境。所有的依赖版本均严格定义在 `pixi.toml` 中。
## Prerequisite
如果你不想使用 pixi请参考下方的 [Manual Build](#manual-build) 章节。
本小节介绍编译 clice 的前置依赖。
## Quick Start
### Toolchain
请参考 [pixi](https://pixi.prefix.dev/latest/installation) 官方指南安装 pixi。
- clang >= 19
- c++23 compitable standard library
- MSVC STL >= 19.44(VS 2022 17.4)
- GCC libstdc++ >= 14
- Clang libc++ >= 20
clice 使用 C++23 作为语言标准 ,请确保有可用的 clang 19 以及以上的编译器,以及兼容 C++23 的标准库。
我们内置了一系列任务,以下命令可直接完成编译并运行测试:
> clice 暂时只能使用 clang 编译,在未来我们会改进这一点,使其能使用 gcc 和 msvc 编译。
```shell
# configure && build (default RelWithDebInfo)
pixi run build
### LLVM Libs
- 20.1.5 <= llvm libs < 21
由于 C++ 的语法太过复杂,自己编写一个新的 parser 是不现实的。clice 调用 clang 的 API 来 parse C++ 源文件获取 AST这意味它需要链接 llvm/clang libs。另外由于 clice 使用了 clang 的私有头文件,这些私有头文件在 llvm 发布的 binary release 中是没有的,所以不能直接使用系统的 llvm package。
如果你能找到系统的 llvm package 对应的 llvm commit将该 commit 下的如下三个文件
- `clang/lib/Sema/CoroutineStmtBuilder.h`
- `clang/lib/Sema/TypeLocBuilder.h`
- `clang/lib/Sema/TreeTransform.h`
拷贝到 `LLVM_INSTALL_PATH/include/clang/Sema/` 中即可。
除了这种方法以外,还有两种办法获取 clice 所需的 llvm libs
1. 使用我们提供的预编译版本
```bash
# .github/workflows/cmake.yml
# Linux precompiled binary require glibc 2.35 (build on ubuntu 22.04)
$ mkdir -p ./.llvm
$ curl -L "https://github.com/clice-project/llvm-binary/releases/download/20.1.5/x86_64-linux-gnu-release.tar.xz" | tar -xJ -C ./.llvm
# MacOS precompiled binary require macos15+
$ mkdir -p ./.llvm
$ curl -L "https://github.com/clice-project/llvm-binary/releases/download/20.1.5/arm64-macosx-apple-release.tar.xz" | tar -xJ -C ./.llvm
# Windows precompiled binary only MD runtime support
$ curl -O -L "https://github.com/clice-project/llvm-binary/releases/download/20.1.5/x64-windows-msvc-release.7z"
$ 7z x x64-windows-msvc-release.7z "-o.llvm"
# unit && integration
pixi run test
```
> [!IMPORTANT]
>
> 对于 debug 版本的 llvm libs构建的时候我们开启了 address sanitizer而 address sanitizer 依赖于 compiler rt它对编译器版本十分敏感。所以如果使用 debug 版本,请确保你的 clang 的 compiler rt 版本和我们构建的时候**严格一致**。
>
> - Windows 暂时无 debug 构建的 llvm libs因为它不支持将 clang 构建为动态库,相关的进展可以在 [这里](https://discourse.llvm.org/t/llvm-is-buildable-as-a-windows-dll/87748) 找到
> - Linux 使用 clang20
> - MacOS 使用 homebrew llvm@20一定不要使用 apple clang
细粒度任务:上述命令由多个子任务组成,你也可以单独运行它们,并支持通过第一个参数指定构建类型:
2. 自己从头编译 llvm/clang
这是最推荐的方式,可以保证环境一致性,避免因为 ABI 不一致而导致的崩溃问题。我们提供了一个脚本,用于构建 clice 所需要的 llvm libs[build-llvm-libs.py](https://github.com/clice-project/clice/blob/main/scripts/build-llvm-libs.py)。
```bash
$ cd llvm-project
$ python3 <clice>/scripts/build-llvm-libs.py debug
```shell
pixi run cmake-config Debug
pixi run cmake-build Debug
pixi run unit-test Debug
pixi run integration-test Debug
```
也可以参考 llvm 的官方构建教程 [Building LLVM with CMake](https://llvm.org/docs/CMake.html)。
> [!TIP]
> 如果你想直接使用 `cmake`, `ninja`, `clang++` 等命令进行开发,请运行 `pixi shell` 进入已配置好环境变量的终端
## Building
### XMake
在处理好前置依赖之后,可以开始构建 clice 了,我们提供 cmake/xmake 两种构建方式。
我们同样支持使用 XMake 构建:
```shell
# config & build (default releasedbg)
pixi run xmake
# unit & integration
pixi run xmake-test
```
## Manual Build
如果你打算手动构建,请务必先确认你的工具链满足 pixi.toml 中定义的版本要求。
> 兼容性说明:理论上 clice 不依赖特定编译器的扩展可以使用主流编译器GCC/Clang/MSVC编译。但我们仅在 CI 中保证特定版本的 Clang 能通过测试。对于其他编译器或版本,我们提供**尽力而为 (Best Effort)** 的支持。如果遇到问题,欢迎提交 Issue 或 PR
### CMake
下面是 clice 支持的 cmake 参数
- `LLVM_INSTALL_PATH` 用于指定 llvm libs 的安装路径
- `CLICE_ENABLE_TEST` 是否构建 clice 的单元测试
例如
```bach
$ cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DLLVM_INSTALL_PATH="./.llvm" -DCLICE_ENABLE_TEST=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
$ cmake --build build
```
### Xmake
使用如下的命令即可构建 clice
```bash
$ xmake f -c --dev=true --mode=debug --toolchain=clang --llvm="./.llvm" --enable_test=true
$ xmake build --all
```
> --llvm 是可选的如果不指定的话xmake 会自动下载我们编译好的预编译二进制
## Run Tests
clice 有两种形式的测试,单元测试和集成测试。
- 运行单元测试
```bash
$ ./build/bin/unit_tests --test-dir="./tests/data" --resource-dir="<LLVM_INSTALL_PATH>/lib/clang/20"
```
- 运行集成测试
```bash
$ pytest -s --log-cli-level=INFO tests/integration --executable=./build/bin/clice --resource-dir="<LLVM_INSTALL_PATH>/lib/clang/20"
```
> resource-dir 是 clang 的内置头文件文件夹
或者,如果你使用 xmake 作为构建系统,可以直接通过 xmake 运行测试
```shell
$ xmake test --verbose
$ xmake run unit_tests --verbose
$ xmake test integration_tests/default --verbose
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain.cmake \
-DCLICE_ENABLE_TEST=ON
```
> 注意:`CMAKE_TOOLCHAIN_FILE` 是可选的。如果你使用的工具链与我们完全一致,可以使用预定义的 `cmake/toolchain.cmake`,否则请移除该选项
可选的构建选项:
| 选项 | 默认值 | 效果 |
| -------------------- | ------ | -------------------------------------------------------------------------------------------------- |
| LLVM_INSTALL_PATH | "" | 使用自定义路径的 LLVM 库来构建 clice |
| CLICE_ENABLE_TEST | OFF | 是否构建 clice 的单元测试 |
| CLICE_USE_LIBCXX | OFF | 是否使用 libc++ 来构建 clice添加 `-std=libc++`),如果开启,请确保 LLVM 库也是使用 libc++ 编译的 |
| CLICE_CI_ENVIRONMENT | OFF | 是否打开 `CLICE_CI_ENVIRONMENT` 这个宏,有些测试在 CI 环境才会执行 |
| CLICE_BUILTIN_LIBRARY_MODULES | "" | 以分号分隔的 CMake 模块列表,用于注册会被编译进 `clice` 的 builtin library详见 [Builtin Libraries](./builtin-library.md) |
### XMake
使用如下命令即可构建 clice
```bash
xmake f -c --mode=releasedbg --toolchain=clang
xmake build --all
```
可选的构建选项:
| 选项 | 默认值 | 效果 |
| ------------- | ------ | ------------------------------------ |
| --llvm | "" | 使用自定义路径的 LLVM 库来构建 clice |
| --enable_test | false | 是否构建 clice 的单元测试 |
| --ci | false | 是否打开 `CLICE_CI_ENVIRONMENT` |
## About LLVM
clice 调用 Clang API 来解析 C++ 代码,因此必须链接 LLVM/Clang 库。由于 clice 使用了 Clang 的私有头文件(这些文件通常不包含在发行版中),不能直接使用系统安装的 LLVM 包。
主要有两种方式解决这个依赖问题:
1. 我们在 [clice-llvm](https://github.com/clice-io/clice-llvm/releases) 上会发布使用的 LLVM 版本的预编译二进制,用于 CI 或者 release 构建。在构建时 cmake 和 xmake 默认会从此处下载 LLVM 库然后使用。
> [!IMPORTANT]
>
> 对于 debug 版本的 LLVM 库,构建的时候我们开启了 address sanitizer而 address sanitizer 依赖于 compiler rt它对编译器版本十分敏感。所以如果使用 debug 版本,请确保你的 clang 的 compiler rt 版本与 `pixi.toml` 中的定义严格一致。
2. 自行构建一套与当前环境一致的 LLVM/Clang。如果默认的预编译二进制文件在你的系统上因 ABI 或库版本不兼容而运行失败,或者你需要一个自定义的 Debug 版本,那么我们推荐你使用此方法从头编译 LLVM 库。我们提供了一个脚本 `scripts/build-llvm.py` 用于构建所需要的 LLVM 库,也可以参考 LLVM 的官方构建教程 [Building LLVM with CMake](https://llvm.org/docs/CMake.html)。

View File

@@ -0,0 +1,101 @@
# Builtin Libraries
Builtin library 会被直接编译进 `clice` 可执行文件,而不是在运行时通过 `--plugin-path` 动态加载。
这种方式适合以下场景:
- 插件源码位于 `clice` 源码树之外
- 希望该 builtin 默认随 `clice` 可执行文件一起发布
- 需要为该 builtin 单独补充 include 路径、编译宏或链接依赖
## CMake 入口
`clice` 现在提供了一个辅助模块:[cmake/builtin-libraries.cmake](/cmake/builtin-libraries.cmake)。
额外的 builtin library 通过缓存变量 `CLICE_BUILTIN_LIBRARY_MODULES` 注册。
`CLICE_BUILTIN_LIBRARY_MODULES` 中的每一项都必须是一个 CMake 文件。配置阶段 `clice``include()` 这些文件,而每个文件都需要调用 `clice_add_builtin_library(...)`
## 最小示例
你可以在外部项目中创建一个 CMake 文件,例如 `/path/to/my-plugin/clice-builtin.cmake`
```cmake
clice_add_builtin_library(
NAME my_plugin
SOURCES
"${CMAKE_CURRENT_LIST_DIR}/src/MyPlugin.cpp"
INCLUDE_DIRECTORIES
"${CMAKE_CURRENT_LIST_DIR}/include"
ENTRYPOINT
clice_get_my_plugin_server_plugin_info
)
```
然后在配置 `clice` 时传入:
```shell
cmake -B build -G Ninja \
-DCLICE_BUILTIN_LIBRARY_MODULES="/path/to/my-plugin/clice-builtin.cmake"
```
如果要加载多个模块,可以传入以分号分隔的 CMake 列表:
```shell
cmake -B build -G Ninja \
-DCLICE_BUILTIN_LIBRARY_MODULES="/path/to/a.cmake;/path/to/b.cmake"
```
## `clice_add_builtin_library`
该辅助函数支持以下参数:
| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `NAME` | 是 | 逻辑名称,会用于创建内部 object target |
| `SOURCES` | 是 | 要编译进 `clice` 的源文件,支持绝对路径和源码树外路径 |
| `ENTRYPOINT` | 是 | `clice` 命名空间中的唯一函数名,返回值类型为 `::clice::PluginInfo` |
| `INCLUDE_DIRECTORIES` | 否 | 仅对当前 builtin 生效的额外头文件目录 |
| `LINK_LIBRARIES` | 否 | 当前 builtin 额外需要的库或 target |
| `COMPILE_DEFINITIONS` | 否 | 当前 builtin 额外需要的编译宏 |
| `COMPILE_OPTIONS` | 否 | 当前 builtin 额外需要的编译选项 |
## Entrypoint 要求
所有 builtin library 最终都会被链接进同一个可执行文件,因此每个 builtin 都必须在 `clice` 命名空间中使用唯一的入口函数名。
动态插件通常使用:
```cpp
clice_get_server_plugin_info()
```
builtin library 应该改用类似下面的唯一名字:
```cpp
clice_get_my_plugin_server_plugin_info()
```
例如:
```cpp
#include "Server/Plugin.h"
namespace clice {
::clice::PluginInfo clice_get_my_plugin_server_plugin_info() {
return {
CLICE_PLUGIN_API_VERSION,
"MyPlugin",
"v0.0.1",
CLICE_PLUGIN_DEF_HASH,
[](clice::ServerPluginBuilder& builder) {
// 在这里注册回调
},
};
}
} // namespace clice
```
`clice` 会自动生成静态注册代码,因此只要模块被包含进来,就不需要再手动修改 `src/clice.cc`

View File

@@ -2,10 +2,11 @@
我们欢迎任何贡献!
请参考 [build](./build.md) 来构建 clice
请参考 [build](./build.md) 来构建 clice,参考 [test and debug](./test-and-debug.md) 来测试和调试 clice。
## Code Style
命名
- 变量名:小写下换线
- 类名,枚举名:大驼峰
- 类名,枚举名:大驼峰

70
docs/zh/dev/extension.md Normal file
View File

@@ -0,0 +1,70 @@
# Extension
本节汇总各编辑器插件的开发与发布流程。目前包含 VSCode / Neovim / Zed。
## VSCode
VSCode 插件使用 Node/PNPM/VSCE 链路。推荐在 pixi 的 `node` 环境下操作以获得一致的工具链版本。
```shell
# 准备环境(先安装 pixi
pixi shell -e node
# 安装依赖(基于 pnpm-lock
pixi run install-vscode
# 打包扩展,产物位于 editors/vscode/*.vsix
pixi run build-vscode
```
发布到 VSCode Marketplace需要 `VSCE_PAT` 环境变量):
```shell
pixi run publish-vscode
```
> [!TIP]
> 若已编译 clice本地调试时可在 VSCode 设置中填写 `clice.executable`,使扩展指向你的自定义构建。
开发与调试:
1. `pixi shell -e node`
2.`editors/vscode` 下运行 `pnpm run watch`(增量构建)
3. VSCode 中使用 “Run Extension/Launch Extension” 调试配置,或执行 `code --extensionDevelopmentPath=$(pwd)/editors/vscode`
常用脚本(在 `pixi shell -e node` 下):
```bash
pnpm run package # 等价于 pixi run build-vscode
pnpm run publish # 等价于 pixi run publish-vscode
```
如果不使用 pixi请自行准备 node.js >= 20、pnpm然后在 `editors/vscode` 目录执行:
```bash
pnpm install
pnpm run package
```
## Neovim
Neovim 插件位于 `editors/nvim`,使用 Lua 编写。目前功能仍在演进中。
- 将仓库路径加入 `runtimepath`,例如:`set rtp+=/path/to/clice/editors/nvim`
- 或在本地创建软链接:`~/.config/nvim/pack/clice/start/clice` -> `<repo>/editors/nvim`
- 需要 `clice` 可执行文件可在 `$PATH` 中被找到
开发提示:代码量较小,可直接在 Neovim 中加载并通过 `:messages`/LSP 日志观察效果;格式化可使用 `stylua`(仓库中已提供 `stylua.toml`)。
## Zed
Zed 插件位于 `editors/zed`,使用 Rust 和 `zed_extension_api`
建议的本地验证流程:
```bash
cd editors/zed
cargo build --release
```
随后按 Zed 官方指南加载本地扩展(需安装 Zed CLI在启动前确保 `clice` 已在 PATH 中。发布时同样遵循 Zed 扩展发布流程。

View File

@@ -0,0 +1,78 @@
你可以在 clice 中实现一个 server plugin 来扩展 clice 的功能。
## 用例
当你使用 `clice` 作为 LLM 代理的 LSP 后端时,比如 claude code你可以添加插件来提供一些额外功能。
## 编写插件
当一个插件被服务器加载时,它会调用 `clice_get_server_plugin_info` 来获取关于这个插件的信息以及如何注册它的定制点。
这个函数需要由插件实现,请参考下面的示例:
```cpp
extern "C" ::clice::PluginInfo LLVM_ATTRIBUTE_WEAK
clice_get_server_plugin_info() {
return {
CLICE_PLUGIN_API_VERSION, "MyPlugin", "v0.1", CLICE_PLUGIN_DEF_HASH,
[](ServerPluginBuilder builder) { ... }
};
}
```
请参考 [PluginProtocol.h](/include/Server/PluginProtocol.h) 了解更多细节。
## 编译插件
插件必须使用与 clice 一致的依赖和编译器选项来编译,否则会导致 undefined behavior。[config/llvm-manifest.json](/config/llvm-manifest.json) 中定义了 clice 使用的构建信息。
## 加载插件
为了安全考虑clice 不允许通过配置文件来加载插件,而必须通过命令行选项来指定插件的路径。
`clice` 启动时,它会加载所有在命令行中指定的插件。你可以通过 `--plugin-path` 选项来指定插件的路径。
```shell
$ clice --plugin-path /path/to/my-plugin.so
```
## 获取 `CLICE_PLUGIN_DEF_HASH` 的内容
`clice_get_server_plugin_info` 函数中需要返回两个值。
- `CLICE_PLUGIN_API_VERSION` 用于确保插件和服务器之间的 `clice_get_server_plugin_info` 函数的一致性。
- `CLICE_PLUGIN_DEF_HASH` 用于确保插件和服务器之间的 C++ 声明的一致性。
要调试 `CLICE_PLUGIN_DEF_HASH` 的内容,你可以运行以下命令:
```shell
$ git clone https://github.com/clice-io/clice.git
$ cd clice
$ git checkout `clice --version --git-describe`
$ python scripts/plugin-def.py content > /tmp/plugin-proto.h
```
你将会得到一个 C 源码格式的文件,内容大致如下:
```cpp
#if 0
// begin of config/llvm-manifest.json
[
{
"version": "21.1.4+r1",
"filename": "arm64-macos-clang-debug-asan.tar.xz",
"sha256": "7da4b7d63edefecaf11773e7e701c575140d1a07329bbbb038673b6ee4516ff5",
"lto": false,
"asan": true,
"platform": "macosx",
"build_type": "Debug"
},
...
]
...
#endif
```
## Builtin libraries
如果你希望把插件直接编译进 `clice` 可执行文件,而不是在运行时动态加载,请参考 [Builtin Libraries](./builtin-library.md)。

View File

@@ -0,0 +1,84 @@
# Test and Debug
## Run Tests
clice 有两种形式的测试,单元测试和集成测试。
- 运行单元测试
```bash
$ ./build/bin/unit_tests --test-dir="./tests/data"
```
- 运行集成测试
我们使用 pytest 来运行集成测试,请参考 `pyproject.toml` 安装依赖的 python 库
```bash
$ pytest -s --log-cli-level=INFO tests/integration --executable=./build/bin/clice
```
如果你使用 xmake 作为构建系统,可以直接通过 xmake 运行测试:
```shell
$ xmake run --verbose unit_tests
$ xmake test --verbose integration_tests/default
```
## Debug
如果想在 clice 上附加调试器并进行调试,推荐先单独以 socket 模式启动 clice然后再将客户端连接到 clice 上
```shell
$ ./build/bin/clice --mode=socket --port=50051
```
在服务器启动之后,可以通过以下两种方式启动客户端连接到服务器
- 使用 pytest 运行特定测试进行连接
你可以运行一个单独的集成测试用例来连接正在运行的 clice。这对于复现和调试特定场景非常有用。
```shell
$ pytest -s --log-cli-level=INFO tests/integration/test_file_operation.py::test_did_open --mode=socket --port=50051
```
- 使用 vscode 进行实际的测试
你也可以通过配置 clice-vscode 插件来连接正在运行的 clice 服务,从而在实际使用场景中进行调试。
1. 在插件市场下载插件 [clice-vscode](https://marketplace.visualstudio.com/items?itemName=ykiko.clice-vscode)
2. 配置 `settings.json`: 在你的项目根目录下创建 `.vscode/settings.json` 文件,并填入以下内容:
```jsonc
{
// Point this to the clice binary you downloaded.
"clice.executable": "/path/to/your/clice/executable",
// Enable socket mode.
"clice.mode": "socket",
"clice.port": 50051,
// Optional: Set this to an empty string to turn off the clangd.
"clangd.path": "",
}
```
3. 重新加载窗口:修改配置后,在 vscode 中执行 Developer: Reload Window 命令使配置生效。插件会自动连接到正在 50051 端口监听的 clice。
如果你需要修改或调试 clice-vscode 插件本身,可以按以下步骤操作:
1. 克隆并安装依赖:
```shell
$ git clone https://github.com/clice-io/clice-vscode
$ cd clice-vscode
$ npm install
```
2. 使用 vscode 打开插件项目:用一个新的 vscode 窗口打开 clice-vscode 文件夹
3. 创建调试配置:在 clice-vscode 项目中,也创建一个 `.vscode/settings.json` 文件,内容与上方相同
4. 按下 `F5` 键。这会启动一个【扩展开发宿主】窗口。这是一个加载了你本地 clice-vscode 插件代码的新的 vscode 窗口,在这个新窗口中打开你的 C++ 项目,它应该会自动连接到 clice

View File

@@ -2,91 +2,51 @@
这是 `clice.toml` 的文档。
## Server
## Project
| 名称 | 类型 | 默认值 |
| ------------------- | -------- | ----------------------------- |
| `project.cache_dir` | `string` | `"${workspace}/.clice/cache"` |
用于储存 PCH 和 PCM 缓存的文件夹。
<br>
| 名称 | 类型 | 默认值 |
| ------------------- | -------- | ----------------------------- |
| `project.index_dir` | `string` | `"${workspace}/.clice/index"` |
用于储存索引文件的文件夹。
<br>
## Rule
`[[rules]]` 表示一个对象数组,其中每个对象都拥有下面这些属性
<br>
| 名称              | 类型                |
| ----------------- | ------------------- |
| `[rules].pattern` | `array` of `string` |
| 名称 | 类型 |
| ------------------ | ------------------- |
| `[rules].patterns` | `array` of `string` |
用于匹配文件路径的 glob patterns遵循 LSP 的 [标准](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentFilter)。
- `*`: 匹配路径段中的一个或多个字符。
- `?`: 匹配路径段中的单个字符。
- `**`: 匹配任意数量的路径段,包括零个。
- `{}`: 用于分组条件 (例如, `**/*.{ts,js}` 匹配所有 TypeScript 和 JavaScript 文件)。
- `[]`: 声明要匹配的路径段中的字符范围 (例如, `example.[0-9]` 匹配 `example.0`, `example.1` 等)。
- `[!...]`: 排除要匹配的路径段中的字符范围 (例如, `example.[!0-9]` 匹配 `example.a`, `example.b`,但不匹配 `example.0`)。
<br>
- `{}`: 用于分组条件 (例如`**/*.{ts,js}` 匹配所有 TypeScript 和 JavaScript 文件)。
- `[]`: 声明要匹配的路径段中的字符范围 (例如`example.[0-9]` 匹配 `example.0`, `example.1` 等)。
- `[!...]`: 排除要匹配的路径段中的字符范围 (例如`example.[!0-9]` 匹配 `example.a`, `example.b`,但不匹配 `example.0`)。
<br>
| 名称             | 类型                | 默认值 |
| ---------------- | ------------------- | ------- |
| `[rules].append` | `array` of `string` | `[]`    |
| 名称 | 类型 | 默认值 |
| ---------------- | ------------------- | ------ |
| `[rules].append` | `array` of `string` | `[]` |
追加到原始命令列表中的命令。例如,`append = ["-std=c++17"]`
<br>
| 名称             | 类型                | 默认值 |
| ---------------- | ------------------- | ------- |
| `[rules].remove` | `array` of `string` | `[]`    |
| 名称 | 类型 | 默认值 |
| ---------------- | ------------------- | ------ |
| `[rules].remove` | `array` of `string` | `[]` |
从原始命令列表中移除的命令。例如,`remove = ["-std=c++11"]`
<br>
| 名称               | 类型     | 默认值  |
| ------------------ | -------- | -------- |
| `[rules].readonly` | `string` | `"auto"` |
控制文件是否被视为只读。值可以是 `"auto"``"always"``"never"` 中的一个。
- `"auto"`: 在你编辑文件之前,文件被视为只读。
- `"always"`: 始终将文件视为只读。
- `"never"`: 始终将文件视为非只读。
只读意味着文件不可编辑,并且像代码操作 (code actions) 或补全 (completions) 这样的 LSP 请求不会在其上触发。这避免了动态计算,并允许直接加载预先索引的结果,从而提高性能。
<br>
| 名称             | 类型     | 默认值  |
| ---------------- | -------- | -------- |
| `[rules].header` | `string` | `"auto"` |
控制如何处理头文件。值可以是 `"auto"``"always"``"never"` 中的一个。
- `"auto"`: 首先尝试推断头文件上下文。如果未找到头文件上下文,文件将被视为普通的源文件。
- `"always"`: 始终将文件视为头文件。如果未找到头文件上下文,将会报告错误。
- `"never"`: 始终将文件视为源文件。
头文件上下文指的是与该头文件相关联的源文件或其他元数据。
<br>
| 名称               | 类型                | 默认值 |
| ------------------ | ------------------- | ------- |
| `[rules].contexts` | `array` of `string` | `[]`    |
为文件指定额外的头文件上下文 (文件路径)。
通常,一旦文件被索引,头文件上下文会自动推断。但是,如果你需要在索引完成前获得即时上下文,可以使用此字段手动提供。
## Cache
| 名称        | 类型     | 默认值                       |
| ----------- | -------- | ----------------------------- |
| `cache.dir` | `string` | `"${workspace}/.clice/cache"` |
用于储存 PCH 和 PCM 缓存的文件夹。
<br>
## Index
| 名称        | 类型     | 默认值                       |
| ----------- | -------- | ----------------------------- |
| `index.dir` | `string` | `"${workspace}/.clice/index"` |
用于储存索引文件的文件夹。
<br>
## Feature

View File

@@ -26,7 +26,6 @@ clice 实现了 [Language Server Protocol](https://microsoft.github.io/language-
自己从源码编译 clice具体的步骤参考 [build](../dev/build.md)。
## Project Setup
为了让 clice 能正确理解你的代码(例如找到头文件的位置),需要为 clice 提供一份 `compile_commands.json` 文件,也就说所谓的 [编译数据库](https://clang.llvm.org/docs/JSONCompilationDatabase.html)。编译数据库中提供了每个源文件的编译选项。
@@ -47,7 +46,11 @@ cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
### Bazel
TODO:
Bazel 不支持直接生成编译数据库,推荐使用 [bazel-compile-commands-extractor](https://github.com/hedronvision/bazel-compile-commands-extractor)。在安装好之后,你可以这样生成 `compile_commands.json`:
```bash
bazel run @hedron_compile_commands//:refresh_all
```
### Visual Studio
@@ -61,4 +64,4 @@ TODO:
### Others
对于任意其它的构建系统,可以尝试使用 [bear](https://github.com/rizsotto/Bear) 或者 [scan-build](https://github.com/rizsotto/scan-build) 来拦截编译命令并获取到编译数据库(不保证成功)。我们计划在未来编写一个**新的工具**,通过假编译器的方式来实现编译命令的捕获。
对于任意其它的构建系统,可以尝试使用 [bear](https://github.com/rizsotto/Bear) 或者 [scan-build](https://github.com/rizsotto/scan-build) 来拦截编译命令并获取到编译数据库(不保证成功)。我们计划在未来编写一个**新的工具**,通过假编译器的方式来实现编译命令的捕获。

View File

@@ -20,4 +20,4 @@ clice 是一个全新的 C++ 的语言服务器,旨在解决现存 C++ 语言
既然如此,那么像为 clangd [初步支持 C++20 module](https://github.com/llvm/llvm-project/pull/66462) 这样的大型 PR 被拖了将近一年也就不奇怪了。意识到这个现状之后,我萌生了自己编写一个语言服务器的想法。我估计了一下项目大小,去除测试代码,大概 2w 行就能完成,是一个人花一段时间能完成的工作量,而且也有先例,例如 ccls 和 rust analyzer。另外一点就是 clangd 的代码已经上了年代了,尽管有非常多的注释,但是相关的逻辑仍然很绕,进行大范围修改所花费的时间可能还不如重写来得快。
于是说干就干,我对 clangd 的几百个 issue 进行了分类,看看有没有一些问题是因为 clangd 一开始的架构设计错误而导致很难解决,然后被搁置的。如果有的话,是否能在重新设计的时候就考虑这个问题来解决呢?我发现,确实有一些!于是接下来的时间里,我花了大概两个月的时间来学习研究 clang 里面相关的机制,摸索相关问题的解决方法,探索原型实现,在确定相关的问题基本都可以解决之后,正式开始了 clice 的开发。
于是说干就干,我对 clangd 的几百个 issue 进行了分类,看看有没有一些问题是因为 clangd 一开始的架构设计错误而导致很难解决,然后被搁置的。如果有的话,是否能在重新设计的时候就考虑这个问题来解决呢?我发现,确实有一些!于是接下来的时间里,我花了大概两个月的时间来学习研究 clang 里面相关的机制,摸索相关问题的解决方法,探索原型实现,在确定相关的问题基本都可以解决之后,正式开始了 clice 的开发。

View File

@@ -16,8 +16,8 @@ hero:
text: 参与贡献
link: /zh/dev/contribution
image:
src: /image.png
alt: clice
src: /image.png
alt: clice
features:
- icon: T
@@ -32,4 +32,4 @@ features:
- icon: I
title: 内存占用更低,速度更快
details: 优秀的异步任务调度,支持编译任务取消,缓存必要的信息,避免无意义的 CPU 浪费
---
---

3
editors/nvim/README.md Normal file
View File

@@ -0,0 +1,3 @@
# clice-nvim
Provide extended functionality for [clice](https://github.com/clice-io/clice)

View File

@@ -0,0 +1,32 @@
-- Should be placed under config_dir/lsp/
-- Lsp configuration for nvim >= 0.11
local clice = {
filetypes = { 'c', 'cpp' },
root_markers = {
'.git/',
'clice.toml',
'.clang-tidy',
'.clang-format',
'compile_commands.json',
'compile_flags.txt',
'configure.ac', -- AutoTools
},
capabilities = {
textDocument = {
completion = {
editsNearCursor = true,
},
},
offsetEncoding = { 'utf-8' },
},
cmd = {
'clice',
'--mode=pipe',
},
}
return clice

View File

View File

@@ -0,0 +1,3 @@
local augroup = vim.api.nvim_create_augroup('LspClice', { clear = true })
-- TODO: CallHierarchy, TypeHierarchy, LspDump?, ShowHeaderContext?

6
editors/nvim/stylua.toml Normal file
View File

@@ -0,0 +1,6 @@
column_width = 160
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 4
quote_style = "AutoPreferSingle"
call_parentheses = "None"

View File

@@ -0,0 +1,5 @@
import { defineConfig } from '@vscode/test-cli';
export default defineConfig({
files: 'out/test/**/*.test.js',
});

View File

@@ -0,0 +1,9 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"dbaeumer.vscode-eslint",
"amodio.tsl-problem-matcher",
"ms-vscode.extension-test-runner"
]
}

17
editors/vscode/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,17 @@
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"preLaunchTask": "${defaultBuildTask}"
}
]
}

13
editors/vscode/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,13 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false, // set this to true to hide the "out" folder with the compiled JS files
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
},
"search.exclude": {
"out": true, // set this to false to include "out" folder in search results
"dist": true // set this to false to include "dist" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off"
}

37
editors/vscode/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,37 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$ts-webpack-watch",
"isBackground": true,
"presentation": {
"reveal": "never",
"group": "watchers"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "watch-tests",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never",
"group": "watchers"
},
"group": "build"
},
{
"label": "tasks: watch-tests",
"dependsOn": ["npm: watch", "npm: watch-tests"],
"problemMatcher": []
}
]
}

View File

@@ -0,0 +1,15 @@
.github/
.vscode/**
.vscode-test/**
out/**
node_modules/**
src/**
.gitignore
.yarnrc
webpack.config.js
vsc-extension-quickstart.md
**/tsconfig.json
**/.eslintrc.json
**/*.map
**/*.ts
**/.vscode-test.*

201
editors/vscode/LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

19
editors/vscode/README.md Normal file
View File

@@ -0,0 +1,19 @@
# vscode-clice
This is the vscode extension for [clice](https://github.com/clice-project/clice).
## develop
- install dependencies
```shell
git clone https://github.com/clice-io/clice.git
cd clice/editors/vscode
npm install
```
- package
```shell
npm run package
```

BIN
editors/vscode/clice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

177
editors/vscode/package.json Normal file
View File

@@ -0,0 +1,177 @@
{
"name": "clice-vscode",
"displayName": "clice",
"description": "VSCode extension for clice",
"repository": {
"type": "git",
"url": "https://github.com/clice-project/clice-vscode"
},
"version": "0.1.4",
"publisher": "ykiko",
"icon": "clice.png",
"engines": {
"vscode": "^1.80.0"
},
"categories": [
"Programming Languages",
"Linters",
"Formatters"
],
"keywords": [
"C",
"C++",
"cuda",
"clang"
],
"activationEvents": [
"onLanguage:c",
"onLanguage:cpp",
"onLanguage:cuda-cpp"
],
"contributes": {
"configuration": {
"type": "object",
"title": "C/C++ Language Client",
"properties": {
"clice-client.trace.server": {
"default": "verbose"
},
"clice.executable": {
"type": "string",
"default": "",
"description": "The path of clice executable."
},
"clice.mode": {
"type": "string",
"default": "pipe",
"enum": [
"pipe",
"socket"
],
"description": "How to communicate with clice. pipe or socket. For daily use please use pipe."
},
"clice.host": {
"type": "string",
"default": "127.0.0.1",
"description": "The host to connect to (default: 127.0.0.1)"
},
"clice.port": {
"type": "number",
"default": 50051,
"description": "The port to connect to"
}
}
},
"commands": [],
"semanticTokenTypes": [
{
"id": "character",
"description": "C/C++ character literal (e.g., 'a')",
"superType": "string"
},
{
"id": "directive",
"description": "C/C++ preprocessor directive (e.g., #include)",
"superType": "keyword"
},
{
"id": "header",
"description": "C/C++ header name (e.g., <iostream>)",
"superType": "string"
},
{
"id": "module",
"description": "C++20 module name",
"superType": "namespace"
},
{
"id": "macroParameter",
"description": "C/C++ macro parameter",
"superType": "parameter"
},
{
"id": "union",
"description": "C/C++ union type",
"superType": "struct"
},
{
"id": "field",
"description": "C/C++ field (member variable)",
"superType": "variable"
},
{
"id": "label",
"description": "C/C++ label (for goto)",
"superType": "variable"
},
{
"id": "concept",
"description": "C++20 concept",
"superType": "type"
},
{
"id": "attribute",
"description": "GNU/MSVC/C++11/C23 attribute",
"superType": "macro"
},
{
"id": "paren",
"description": "Parentheses `()`",
"superType": "operator"
},
{
"id": "bracket",
"description": "Brackets `[]`",
"superType": "operator"
},
{
"id": "brace",
"description": "Braces `{}`",
"superType": "operator"
},
{
"id": "angle",
"description": "Angle brackets `<>`",
"superType": "operator"
}
]
},
"main": "./dist/extension.js",
"scripts": {
"compile": "webpack",
"watch": "webpack --watch",
"vscode:prepublish": "webpack --mode production --devtool hidden-source-map",
"package": "vsce package --no-dependencies --baseImagesUrl https://raw.githubusercontent.com/clice-io/clice/main/",
"publish": "vsce publish --no-dependencies --baseImagesUrl https://raw.githubusercontent.com/clice-io/clice/main/",
"pretest": "pnpm run compile",
"test": "vscode-test",
"release:patch": "pnpm version patch -m \"release: v%s\" && git push --follow-tags",
"release:minor": "pnpm version minor -m \"release: v%s\" && git push --follow-tags"
},
"devDependencies": {
"@types/decompress": "^4.2.7",
"@types/mocha": "^10.0.10",
"@types/node": "~25.0.3",
"@types/vscode": "^1.80.0",
"@vscode/test-cli": "^0.0.12",
"@vscode/test-electron": "^2.5.2",
"@vscode/vsce": "^3.7.1",
"ts-loader": "^9.5.4",
"typescript": "~5.5.4",
"webpack": "^5.104.1",
"webpack-cli": "^6.0.1"
},
"dependencies": {
"decompress": "^4.2.1",
"vscode-languageclient": "^9.0.1"
},
"overrides": {
"glob": "^11.1.0"
},
"pnpm": {
"onlyBuiltDependencies": [
"@vscode/vsce-sign",
"keytar"
]
}
}

4373
editors/vscode/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,247 @@
import * as vscode from "vscode";
import * as fs from "fs";
import * as path from "path";
import * as https from "https";
import * as os from "os";
// @ts-ignore
import decompress = require("decompress");
interface GitHubRelease {
tag_name: string;
assets: {
name: string;
browser_download_url: string;
}[];
}
export async function ensureServerBinary(
context: vscode.ExtensionContext,
channel: vscode.OutputChannel,
): Promise<string | undefined> {
const storagePath = context.globalStorageUri.fsPath;
const platform = os.platform();
const arch = os.arch();
channel.appendLine(`[Download] Initializing clice downloader...`);
channel.appendLine(`[Download] Platform: ${platform}, Arch: ${arch}, Storage: ${storagePath}`);
let platformKeyword = "";
let archKeyword = "";
let binaryName = "clice";
if (platform === "win32") {
platformKeyword = "windows";
archKeyword = "x64";
binaryName = "clice.exe";
} else if (platform === "darwin") {
platformKeyword = "macos";
archKeyword = arch;
} else if (platform === "linux") {
platformKeyword = "linux";
archKeyword = arch === "x64" ? "x86_64" : arch;
} else {
const msg = `Unsupported platform: ${platform}`;
channel.appendLine(`[Download] Error: ${msg}`);
vscode.window.showErrorMessage(msg);
return undefined;
}
const executablePath = path.join(storagePath, "bin", binaryName);
if (fs.existsSync(executablePath)) {
channel.appendLine(`[Download] Found existing binary at: ${executablePath}`);
// TODO: check tag update
return executablePath;
}
if (!fs.existsSync(storagePath)) {
channel.appendLine(`[Download] Creating storage directory: ${storagePath}`);
fs.mkdirSync(storagePath, { recursive: true });
}
const statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
try {
statusItem.text = "$(sync~spin) Checking clice updates...";
statusItem.show();
channel.appendLine(`[Download] Fetching latest release from GitHub...`);
const release = await fetchReleaseInfo(channel);
channel.appendLine(`[Download] Latest tag: ${release.tag_name}`);
const asset = release.assets.find((a) => {
const name = a.name.toLowerCase();
return (
name.includes(platformKeyword) &&
name.includes(archKeyword) &&
!name.includes("symbol")
);
});
if (!asset) {
throw new Error(
`No compatible asset found for ${platform}-${archKeyword} in release ${release.tag_name}`,
);
}
channel.appendLine(`[Download] Found asset: ${asset.name}`);
channel.appendLine(`[Download] Download URL: ${asset.browser_download_url}`);
const tempArchiveName = asset.name;
const tempArchivePath = path.join(storagePath, tempArchiveName);
statusItem.text = `$(cloud-download) Downloading clice...`;
await downloadFile(asset.browser_download_url, tempArchivePath, channel);
statusItem.text = `$(file-zip) Extracting...`;
channel.appendLine(`[Download] Extracting ${tempArchivePath} to ${storagePath}...`);
await decompress(tempArchivePath, storagePath);
channel.appendLine(`[Download] Extraction complete.`);
fs.unlinkSync(tempArchivePath);
if (!fs.existsSync(executablePath)) {
throw new Error(`Executable not found at ${executablePath} after extraction.`);
}
if (platform !== "win32") {
channel.appendLine(`[Download] Setting executable permissions (chmod 755)...`);
fs.chmodSync(executablePath, "755");
}
channel.appendLine(`[Download] Setup successful. Binary ready at: ${executablePath}`);
vscode.window.showInformationMessage(
`Clice language server updated to ${release.tag_name}`,
);
return executablePath;
} catch (error) {
channel.appendLine(`[Download] CRITICAL ERROR during setup:`);
if (error instanceof Error) {
channel.appendLine(`[Download] Message: ${error.message}`);
if (error.stack) {
channel.appendLine(`[Download] Stack: ${error.stack}`);
}
} else {
channel.appendLine(`[Download] Unknown error: ${JSON.stringify(error)}`);
}
vscode.window
.showErrorMessage(
`Failed to download clice server. Check "clice" output channel for details.`,
"Open Output",
)
.then((selection) => {
if (selection === "Open Output") {
channel.show();
}
});
return undefined;
} finally {
statusItem.dispose();
}
}
function downloadFile(
url: string,
destPath: string,
channel: vscode.OutputChannel,
maxRedirects = 5,
): Promise<void> {
return new Promise((resolve, reject) => {
if (maxRedirects <= 0) {
reject(new Error("Too many redirects"));
return;
}
const file = fs.createWriteStream(destPath);
channel.appendLine(`[Download] Start downloading to ${destPath}`);
https
.get(url, { headers: { "User-Agent": "VSCode-Extension" } }, (response) => {
if (response.statusCode === 302 || response.statusCode === 301) {
channel.appendLine(`[Download] Redirecting to ${response.headers.location}`);
file.close();
downloadFile(response.headers.location!, destPath, channel, maxRedirects - 1)
.then(resolve)
.catch(reject);
return;
}
if (response.statusCode !== 200) {
reject(new Error(`Download failed with status code ${response.statusCode}`));
return;
}
response.pipe(file);
file.on("finish", () => {
file.close();
channel.appendLine(`[Download] Download finished.`);
resolve();
});
})
.on("error", (err) => {
file.close();
fs.unlink(destPath, () => {});
reject(err);
});
});
}
async function fetchReleaseInfo(channel: vscode.OutputChannel): Promise<GitHubRelease> {
try {
channel.appendLine("[Download] Attempting to fetch latest stable release...");
const release = await fetchJson<GitHubRelease>("/repos/clice-io/clice/releases/latest");
channel.appendLine(`[Download] Found stable release: ${release.tag_name}`);
return release;
} catch (error: any) {
if (error.message && error.message.includes("404")) {
channel.appendLine(
"[Download] Latest stable release not found (404). Checking for pre-releases...",
);
const releases = await fetchJson<GitHubRelease[]>(
"/repos/clice-io/clice/releases?per_page=1",
);
if (Array.isArray(releases) && releases.length > 0) {
const latestPre = releases[0];
channel.appendLine(`[Download] Found pre-release: ${latestPre.tag_name}`);
return latestPre;
} else {
throw new Error("No releases found in repository.");
}
}
throw error;
}
}
function fetchJson<T>(apiPath: string): Promise<T> {
return new Promise((resolve, reject) => {
const options = {
hostname: "api.github.com",
path: apiPath,
headers: { "User-Agent": "VSCode-Extension" },
};
https
.get(options, (res) => {
let data = "";
if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) {
res.resume();
reject(new Error(`GitHub API returned ${res.statusCode} for ${apiPath}`));
return;
}
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
try {
resolve(JSON.parse(data));
} catch (e) {
reject(new Error(`Failed to parse GitHub API response: ${e}`));
}
});
})
.on("error", reject);
});
}

View File

@@ -0,0 +1,95 @@
import * as net from "net";
import * as vscode from "vscode";
import { workspace, window, ExtensionContext } from "vscode";
import {
LanguageClient,
LanguageClientOptions,
ServerOptions,
StreamInfo,
} from "vscode-languageclient/node";
import { getSetting } from "./setting";
import { ensureServerBinary } from "./download";
let client: LanguageClient;
export async function registerCommands(client: LanguageClient, context: ExtensionContext) {
context.subscriptions.push(
vscode.commands.registerCommand("clice.restart", async () => {
await client.restart();
}),
);
}
export async function activate(context: ExtensionContext) {
console.log('Congratulations, your extension "clice" is now active!');
const channel = window.createOutputChannel("clice");
const verboseChannel = window.createOutputChannel("clice-verbose");
const setting = getSetting();
if (!setting) {
return;
}
let executable = setting.executable;
let serverOptions: ServerOptions | (() => Promise<StreamInfo>);
if (setting.mode === "pipe") {
if (!executable || executable === "") {
const downloadedPath = await ensureServerBinary(context, channel);
if (downloadedPath) {
executable = downloadedPath;
} else {
window.showErrorMessage("Could not find or download clice executable.");
return;
}
}
let args = ["--mode=pipe"];
serverOptions = {
run: { command: executable, args: args },
debug: { command: executable, args: args },
};
} else if (setting.mode === "socket") {
serverOptions = (): Promise<StreamInfo> => {
return new Promise((resolve, reject) => {
const client = new net.Socket();
client.connect(setting.port, setting.host, () => {
resolve({
reader: client,
writer: client,
});
});
client.on("error", (error) => {
reject(error);
});
});
};
} else {
vscode.window.showErrorMessage("Invalid mode, please set the mode to 'pipe' or 'socket'.");
return;
}
const clientOptions: LanguageClientOptions = {
documentSelector: [{ scheme: "file", language: "cpp" }],
outputChannel: channel,
traceOutputChannel: verboseChannel,
synchronize: {
fileEvents: workspace.createFileSystemWatcher("**/.clientrc"),
},
};
client = new LanguageClient("clice", "clice", serverOptions, clientOptions);
await registerCommands(client, context);
await client.start();
}
export function deactivate(): Thenable<void> | undefined {
if (!client) {
return undefined;
}
let ret = client.stop();
return ret;
}

View File

@@ -0,0 +1,72 @@
import * as vscode from "vscode";
import { DocumentUri } from "vscode-languageclient/node";
let provider: HeaderContextProvider | undefined = undefined;
export type HeaderContext = {
file: string;
index: number;
include: number;
};
export type HeaderContextSwitchParams = {
header: DocumentUri;
context: HeaderContext;
};
export type IncludeLocation = {
line: number;
filename: string;
};
export class TreeItem extends vscode.TreeItem {
children: Array<TreeItem> = [];
context: HeaderContext | undefined = undefined;
}
export class HeaderContextProvider implements vscode.TreeDataProvider<TreeItem> {
private _onDidChangeTreeData: vscode.EventEmitter<TreeItem | undefined | void> =
new vscode.EventEmitter<TreeItem | undefined | void>();
readonly onDidChangeTreeData: vscode.Event<TreeItem | undefined | void> =
this._onDidChangeTreeData.event;
header: string = "";
items: Array<TreeItem> = [];
update(contexts: Array<Array<HeaderContext>>) {
/// Create groups
this.items = contexts.map((contexts) => {
let item = new TreeItem("", vscode.TreeItemCollapsibleState.Expanded);
item.children = contexts.map((context) => {
const uri = vscode.Uri.file(context.file);
let item = new TreeItem(uri, vscode.TreeItemCollapsibleState.None);
item.context = context;
item.iconPath = vscode.ThemeIcon.File;
item.contextValue = "header-context";
return item;
});
return item;
});
this.refresh();
}
refresh(): void {
this._onDidChangeTreeData.fire();
}
getTreeItem(element: TreeItem) {
return element;
}
getChildren(element?: TreeItem) {
return element ? element.children : this.items;
}
}
export function registerHeaderContextView() {
provider = new HeaderContextProvider();
let treeView = vscode.window.createTreeView("header-contexts", {
treeDataProvider: provider,
});
}

View File

@@ -0,0 +1,63 @@
import * as vscode from "vscode";
const rainbowColors = ["#56B6C2", "#61AFEF", "#C678DD", "#E06C75", "#98C379", "#D19A66", "#E5C07B"];
const textEditorDecorationTypes = rainbowColors.map((color) => {
return vscode.window.createTextEditorDecorationType({
color: color,
});
});
export function highlightDocument(
document: vscode.TextDocument,
legend: vscode.SemanticTokensLegend,
semanticTokens: vscode.SemanticTokens,
) {
const editor = vscode.window.activeTextEditor;
if (!editor || editor.document !== document) {
return;
}
const angleIndex = legend?.tokenTypes.indexOf("angle");
const leftIndex = legend?.tokenModifiers.indexOf("left");
const rightIndex = legend?.tokenModifiers.indexOf("right");
if (leftIndex === undefined || rightIndex === undefined || angleIndex === undefined) {
return;
}
const decorations = new Map<number, vscode.Range[]>();
let level = 0;
let lastLine = 0;
let lastStart = 0;
// [line, startCharacter, length, tokenType, tokenModifiers]
for (let i = 0; i < semanticTokens.data.length; i += 5) {
const [lineDelta, startDelta, length, tokenType, tokenModifiers] =
semanticTokens.data.slice(i, i + 5);
lastLine += lineDelta;
lastStart = lineDelta === 0 ? lastStart + startDelta : startDelta;
const range = new vscode.Range(lastLine, lastStart, lastLine, lastStart + length);
if (tokenType === angleIndex) {
if (tokenModifiers & (1 << rightIndex)) {
level -= 1;
}
if (decorations.has(level % rainbowColors.length)) {
decorations.get(level % rainbowColors.length)?.push(range);
} else {
decorations.set(level % rainbowColors.length, [range]);
}
if (tokenModifiers & (1 << leftIndex)) {
level += 1;
}
}
}
for (const [level, ranges] of decorations) {
editor.setDecorations(textEditorDecorationTypes[level], ranges);
}
}

View File

@@ -0,0 +1,34 @@
import * as vscode from "vscode";
interface Setting {
executable: string | undefined;
mode: string;
host: string;
port: number;
}
export function getSetting(): Setting | undefined {
const setting = vscode.workspace.getConfiguration("clice");
const executable = setting.get<string>("executable");
const mode = setting.get<string>("mode");
if (mode !== "pipe" && mode !== "socket") {
vscode.window.showErrorMessage(`Unexpected mode: ${mode}`);
return undefined;
}
const host = setting.get<string>("host")!;
const port = setting.get<number>("port")!;
if (mode === "socket" && (!host || !port)) {
vscode.window.showErrorMessage("Socket mode requires both host and port to be configured.");
return undefined;
}
return {
executable,
mode,
host,
port,
};
}

View File

@@ -0,0 +1,15 @@
import * as assert from "assert";
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from "vscode";
// import * as myExtension from '../../extension';
suite("Extension Test Suite", () => {
vscode.window.showInformationMessage("Start all tests.");
test("Sample test", () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
});

View File

@@ -0,0 +1,14 @@
{
"compilerOptions": {
"module": "Node16",
"target": "ES2022",
"lib": ["ES2022"],
"sourceMap": true,
"rootDir": "src",
"strict": true /* enable all strict type-checking options */
/* Additional Checks */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
}
}

View File

@@ -0,0 +1,48 @@
//@ts-check
"use strict";
const path = require("path");
//@ts-check
/** @typedef {import('webpack').Configuration} WebpackConfig **/
/** @type WebpackConfig */
const extensionConfig = {
target: "node", // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
mode: "none", // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
entry: "./src/extension.ts", // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
output: {
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
path: path.resolve(__dirname, "dist"),
filename: "extension.js",
libraryTarget: "commonjs2",
},
externals: {
vscode: "commonjs vscode", // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
// modules added here also need to be added in the .vscodeignore file
},
resolve: {
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
extensions: [".ts", ".js"],
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: "ts-loader",
},
],
},
],
},
devtool: "nosources-source-map",
infrastructureLogging: {
level: "log", // enables logging required for problem matchers
},
};
module.exports = [extensionConfig];

1
editors/zed/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

329
editors/zed/Cargo.lock generated Normal file
View File

@@ -0,0 +1,329 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "anyhow"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
[[package]]
name = "bitflags"
version = "2.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "id-arena"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
[[package]]
name = "indexmap"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9"
dependencies = [
"equivalent",
"hashbrown",
"serde",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "leb128"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "proc-macro2"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "semver"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.143"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "spdx"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e17e880bafaeb362a7b751ec46bdc5b61445a188f80e0606e68167cd540fa3"
dependencies = [
"smallvec",
]
[[package]]
name = "syn"
version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "wasm-encoder"
version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a"
dependencies = [
"leb128",
]
[[package]]
name = "wasm-metadata"
version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fd83062c17b9f4985d438603cde0a5e8c5c8198201a6937f778b607924c7da2"
dependencies = [
"anyhow",
"indexmap",
"serde",
"serde_derive",
"serde_json",
"spdx",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasmparser"
version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708"
dependencies = [
"bitflags",
"indexmap",
"semver",
]
[[package]]
name = "wit-bindgen"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "288f992ea30e6b5c531b52cdd5f3be81c148554b09ea416f058d16556ba92c27"
dependencies = [
"bitflags",
"wit-bindgen-rt",
"wit-bindgen-rust-macro",
]
[[package]]
name = "wit-bindgen-core"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e85e72719ffbccf279359ad071497e47eb0675fe22106dea4ed2d8a7fcb60ba4"
dependencies = [
"anyhow",
"wit-parser",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb8738270f32a2d6739973cbbb7c1b6dd8959ce515578a6e19165853272ee64"
[[package]]
name = "wit-bindgen-rust"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a39a15d1ae2077688213611209849cad40e9e5cccf6e61951a425850677ff3"
dependencies = [
"anyhow",
"heck",
"indexmap",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
]
[[package]]
name = "wit-bindgen-rust-macro"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d376d3ae5850526dfd00d937faea0d81a06fa18f7ac1e26f386d760f241a8f4b"
dependencies = [
"anyhow",
"proc-macro2",
"quote",
"syn",
"wit-bindgen-core",
"wit-bindgen-rust",
]
[[package]]
name = "wit-component"
version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "421c0c848a0660a8c22e2fd217929a0191f14476b68962afd2af89fd22e39825"
dependencies = [
"anyhow",
"bitflags",
"indexmap",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "196d3ecfc4b759a8573bf86a9b3f8996b304b3732e4c7de81655f875f6efdca6"
dependencies = [
"anyhow",
"id-arena",
"indexmap",
"log",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
]
[[package]]
name = "zed_clice"
version = "0.1.0"
dependencies = [
"zed_extension_api",
]
[[package]]
name = "zed_extension_api"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "594fd10dd0f2f853eb243e2425e7c95938cef49adb81d9602921d002c5e6d9d9"
dependencies = [
"serde",
"serde_json",
"wit-bindgen",
]

13
editors/zed/Cargo.toml Normal file
View File

@@ -0,0 +1,13 @@
[package]
name = "zed_clice"
version = "0.1.0"
edition = "2021"
license = "MIT"
publish = false
[lib]
crate-type = ["cdylib"]
path = "src/clice.rs"
[dependencies]
zed_extension_api = "0.1.0"

21
editors/zed/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 clice-project
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

5
editors/zed/README.md Normal file
View File

@@ -0,0 +1,5 @@
# clice-zed
This is the zed extension for [clice](https://github.com/clice-io/clice).
Currently, `clice-zed` uses `clice` in environment variables. Support for configuring the clice path in the configuration file may be added in the future.

View File

@@ -0,0 +1,11 @@
id = "clice"
name = "clice"
version = "0.1.0"
schema_version = 1
authors = ["clice-io"]
description = "C++ support"
repository = "https://github.com/clice-io/clice"
[language_servers.clice]
name = "clice"
language = "C++"

44
editors/zed/src/clice.rs Normal file
View File

@@ -0,0 +1,44 @@
use zed_extension_api::{self as zed, LanguageServerId, Result, Worktree};
struct CliceExtension;
struct CliceBinary {
path: String,
}
impl CliceExtension {
fn find_clice_binary(&self, worktree: &Worktree) -> Result<CliceBinary> {
if let Some(path_str) = worktree.which("clice") {
Ok(CliceBinary { path: path_str })
} else {
Err(
"`clice` not found in your PATH. Please install it and add it to your system's PATH environment variable.".to_string()
)
}
}
}
impl zed::Extension for CliceExtension {
fn new() -> Self {
Self
}
// Currently, we only search for the 'clice' binary in the system's PATH.
fn language_server_command(
&mut self,
_language_server_id: &LanguageServerId,
worktree: &Worktree,
) -> Result<zed::Command> {
let binary = self.find_clice_binary(worktree)?;
Ok(zed::Command {
command: binary.path,
args: vec![
"--mode".to_string(),
"pipe".to_string(),
],
env: Default::default(),
})
}
}
zed::register_extension!(CliceExtension);

61
flake.lock generated
View File

@@ -1,61 +0,0 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1738961098,
"narHash": "sha256-yWNBf6VDW38tl179FEuJ0qukthVfB02kv+mRsfUsWC0=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a3eaf5e8eca7cab680b964138fb79073704aca75",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View File

@@ -1,72 +0,0 @@
{
description = "Flake for Clice";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs =
{
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
tomlplusplus = pkgs.tomlplusplus.overrideAttrs (
oldAttrs: {
mesonFlags = oldAttrs.mesonFlags or [] ++ [
"-Dbuild_examples=false"
"-Dbuild_tests=false"
"-Dcompile_library=false"
];
postInstall = oldAttrs.postInstall or "" + ''
cat > "$out/share/pkgconfig/toml++.pc" <<EOF
Name: toml++
Description: Alias for tomlplusplus
Version: ${oldAttrs.version}
Requires: tomlplusplus
EOF
'';
}
);
in
{
devShell = pkgs.mkShell {
buildInputs = [
pkgs.gcc
pkgs.pkg-config
pkgs.xmake
pkgs.cmake
pkgs.ninja
pkgs.python3
pkgs.gtest
pkgs.libuv
pkgs.llvmPackages_20.libstdcxxClang
# pkgs.llvmPackages_20.libllvm
pkgs.llvmPackages_20.bintools
pkgs.llvmPackages_20.compiler-rt
pkgs.llvmPackages_20.libunwind
pkgs.zlib
tomlplusplus
];
shellHook =
let
gcc = pkgs.gcc-unwrapped;
gccInclude = "${gcc}/include";
gccCxxInclude = "${gccInclude}/c++/${gcc.lib.version}";
in
''
export NIX_CFLAGS_COMPILE+=" -isystem ${gccInclude}"
export NIX_CFLAGS_COMPILE+=" -isystem ${gccCxxInclude}"
export NIX_CFLAGS_COMPILE+=" -isystem ${gccCxxInclude}/$(gcc -dumpmachine)"
'';
};
}
);
}

Some files were not shown because too many files have changed in this diff Show More