diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 9bdf02302..000000000 --- a/.dockerignore +++ /dev/null @@ -1,10 +0,0 @@ -# Ignored for `Dockerfile` build tinymist cli -target -node_modules -editors -tools -refs -local -syntaxes -docs -contrib \ No newline at end of file diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 25747a5d9..000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -.zed/settings.json linguist-language=json5 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..74bf44a05 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,59 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior (Library test): +1. Declare a rust test 'fn test_xxx() { ... }' or typescript test 'it_should(function () { ... })' +2. Execute test function +3. See error + +Or (Shell code): + +1. Attach necessary resources to execute shell code +2. Put down some shell code 'cargo run --bin typst-ts-cli -- ...' +3. Execute shell code +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Package/Software version:** + +VSCode version(Help -> About): +```plain +Version: 1.81.1 +Commit: 6c3e3dba23e8fadc360aed75ce363ba185c49794 +Date: 2023-08-09T22:18:39.991Z +Electron: 22.3.18 +ElectronBuildId: 22689846 +Chromium: 108.0.5359.215 +Node.js: 16.17.1 +V8: 10.8.168.25-electron.0 +OS: Linux x64 6.4.12-x64v4-xanmod1 +``` + +tinymist extension version: `v0.7.3` + +**Logs:** + +tinymist server log(Output Panel -> tinymist): +```plain + +``` + +tinymist client log(Help -> Toggle Developer Tools -> Console): +```plain + +``` + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 871e36dfe..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,92 +0,0 @@ -name: Bug report -description: File a bug/issue -labels: ["bug", "need-to-investigate"] -body: -- type: checkboxes - attributes: - label: Is there an existing issue for this? - description: Please search to see if an issue already exists for the bug you encountered. - options: - - label: I have searched the existing issues - required: true -- type: dropdown - attributes: - label: Platform - description: Which platform are you on? - options: - - x64 Windows (win32-x64, Most Common) - - x64 Linux (linux-x64, Most Common) - - Apple Silicon macOS (darwin-arm64, Most Common) - - ARM64 Windows (win32-arm64) - - ARM64 Linux (linux-arm64) - - ARMv7 Linux (linux-armhf) - - Intel macOS (darwin-x64) - - x64 Alpine Linux (alpine-x64) - - ARM64 Alpine Linux (alpine-arm64) - - Browser (web) - - Other Platforms (universal) - validations: - required: true -- type: dropdown - attributes: - label: Editor - description: Which editor are you using? - options: - - VS Cod(e,ium) - - Neovim - - Emacs - - Sublime Text - - Helix - - Zed - - CLI (Command Line Interface) - - Other - validations: - required: true -- type: textarea - attributes: - label: Editor Version - description: | - For example, in VSCode, get the version in (Help -> About) - validations: - required: true -- type: textarea - attributes: - label: Describe the bug - description: A clear and concise description of what the bug is. - validations: - required: true -- type: textarea - attributes: - label: Server Logs - description: | - For example, in Neovim, the log is oftenly stored in the `~/.local/state/nvim/lsp`. - For example, in VSCode, get the logs in (Output Panel -> Tinymist). - We may close a bug report if there is no full logs. Please don't truncate it for us, attach it as a file if it's too long. - value: | - ```log - Paste your logs here - ``` - validations: - required: true -- type: textarea - attributes: - label: Browser Logs - description: | - For example, in VSCode, get the logs in (Help -> Toggle Developer Tools -> Console). - If you open preview in browser, the console log in the browser is also helpful. - We may close a bug report if there is no full logs. Please don't truncate it for us, attach it as a file if it's too long. - value: | - ```log - Paste your logs here - ``` - validations: - required: true -- type: textarea - attributes: - label: Additional context - description: | - Links? References? Anything that will give us more context about the issue you are encountering! - - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index 73b32f33d..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Feature request -description: Create a feature request -labels: ["enhancement", "need-to-investigate"] -body: -- type: textarea - attributes: - label: Motivation - description: | - A brief use case, scenario, or other argument used in support of this *feature*. - validations: - required: false -- type: textarea - attributes: - label: Description - description: | - A clear and concise description of this *feature*. - validations: - required: false -- type: textarea - attributes: - label: More Examples/Questions - description: | - - Using examples to profile how you imagine the *feature* should be - - Raising questions to highlight the uncertain design for the *feature*. - validations: - required: false diff --git a/.github/copilot-instructions-l10n.md b/.github/copilot-instructions-l10n.md deleted file mode 100644 index 73a8ca0bf..000000000 --- a/.github/copilot-instructions-l10n.md +++ /dev/null @@ -1,337 +0,0 @@ -# Localization Instructions for Claude/Copilot - -This document provides comprehensive guidance for adding, updating, and maintaining localization (l10n) in the Tinymist project. - -## Overview - -Tinymist's localization system supports multiple languages across two main components: -- **Rust backend** (`crates/`): Language server functionality -- **VSCode extension** (`editors/vscode/`): Editor integration - -The localization process has two main phases: -1. **Marking and Extracting Messages**: Adding localization calls in code and extracting them -2. **Translating Messages**: Adding translations to locale files - -## Phase 1: Marking and Extracting Messages - -### Rust Backend (`crates/`) - -#### Adding Localized Messages - -Use the `tinymist_l10n::t!` macro with a key and default English message: - -```rust -// Simple message -let message = tinymist_l10n::t!("error.file-not-found", "File not found"); - -// Message with parameters -let message = tinymist_l10n::t!( - "error.invalid-config", - "Invalid configuration: {key}", - key = config_key -); -``` - -**Note**: Use the full `tinymist_l10n::t!` path - no need to import the macro separately. - -#### Key Naming Convention - -Use hierarchical dot-separated keys: -- `component.category.specific-action` -- Examples: - - `tinymist-query.code-action.exportPdf` - - `tinymist.config.badServerConfig` - - `tinymist-project.validate-error.root-path-not-absolute` - -### TypeScript/VSCode Extension (`editors/vscode/`) - -#### Adding Localized Messages - -Use the `l10nMsg` function imported from `../l10n`: - -```typescript -import { l10nMsg } from "../l10n"; - -// Simple message -const message = l10nMsg("Export as PDF"); - -// Message with parameters -const message = l10nMsg("Processing {count} files", { count: fileCount }); -``` - -#### Import Pattern - -Always import `l10nMsg` from the relative path to `l10n.ts`: - -```typescript -import { l10nMsg } from "../l10n"; // Adjust path as needed -``` - -### Extracting Messages - -After adding localized messages to code, extract them using: - -```bash -yarn build:l10n -``` - -This command: -1. Scans Rust and TypeScript files for localization calls -2. Extracts messages to TOML files in `locales/`: - - `locales/tinymist-rt.toml` (Rust messages) - - `locales/tinymist-vscode-rt.toml` (TypeScript messages) -3. Updates existing translations while preserving manual edits - -#### When to Run Extraction - -- **Required**: After adding new localized messages to code -- **Not needed**: When only editing translations in `locales/` files - -## Phase 2: Translating Messages - -### Locale File Format - -Locale files use TOML format designed for easy modification by LLMs: - -```toml -# The translations are partially generated by copilot - -[key.name] -en = "English message" -zh = "Chinese translation" -zh-TW = "Traditional Chinese translation" -fr = "French translation" -``` - -### Available Locale Files - -- `locales/tinymist-vscode.toml` - VSCode extension UI (manual translations) -- `locales/tinymist-vscode-rt.toml` - VSCode extension runtime (auto-extracted) -- `locales/tinymist-rt.toml` - Rust backend runtime (auto-extracted) - -### Adding Translations - -#### Example: Adding a French Translation - -```toml -[extension.tinymist.command.tinymist.exportCurrentPdf] -en = "Export the Opened File as PDF" -zh = "将当前打开的文件导出为 PDF" -fr = "Exporter le fichier ouvert en PDF" # Add this line -``` - -#### Example: Adding Support for a New Language - -```toml -[extension.tinymist.command.tinymist.restartServer] -en = "Restart server" -zh = "重启服务器" -es = "Reiniciar servidor" # New Spanish translation -de = "Server neu starten" # New German translation -``` - -### Translation Guidelines - -1. **Preserve Parameters**: Keep parameter placeholders like `{key}`, `{count}`, `{value}` -2. **Maintain Formatting**: Preserve newlines and special characters -3. **Context Awareness**: Consider the UI context where the message appears -4. **Consistency**: Use consistent terminology across related messages - -### Language Codes - -Use standard language codes: -- `en` - English (required, default) -- `zh` - Simplified Chinese -- `zh-TW` - Traditional Chinese -- `fr` - French -- `de` - German -- `es` - Spanish -- `ja` - Japanese -- `ru` - Russian - -## Examples - -### Example 1: Adding a New Error Message (Rust) - -1. **Add to Rust code**: -```rust -return Err(tinymist_l10n::t!( - "compilation.invalid-syntax", - "Invalid syntax at line {line}", - line = line_number -).into()); -``` - -2. **Extract messages**: -```bash -yarn build:l10n -``` - -3. **Add translations** in `locales/tinymist-rt.toml`: -```toml -[compilation.invalid-syntax] -en = "Invalid syntax at line {line}" -zh = "第 {line} 行语法错误" -fr = "Syntaxe invalide à la ligne {line}" -``` - -### Example 2: Adding a New UI Label (TypeScript) - -1. **Add to TypeScript code**: -```typescript -const exportButton = vscode.window.createQuickPick(); -exportButton.title = l10nMsg("Select Export Format"); -``` - -2. **Extract messages**: -```bash -yarn build:l10n -``` - -3. **Add translations** in `locales/tinymist-vscode-rt.toml`: -```toml -["Select Export Format"] -en = "Select Export Format" -zh = "选择导出格式" -fr = "Sélectionner le format d'exportation" -``` - -### Example 3: Complex Message with Multiple Parameters - -```rust -let message = tinymist_l10n::t!( - "preview.compilation-stats", - "Compiled {pages} pages in {duration}ms", - pages = page_count, - duration = compile_time -); -``` - -Corresponding translation: -```toml -[preview.compilation-stats] -en = "Compiled {pages} pages in {duration}ms" -zh = "在 {duration} 毫秒内编译了 {pages} 页" -fr = "Compilé {pages} pages en {duration}ms" -``` - -## Best Practices - -### When to Localize - -**DO localize:** -- User-facing error messages -- UI labels and buttons -- Status messages -- Command descriptions -- Configuration descriptions - -**DON'T localize:** -- Log messages for developers -- Debug output -- Technical error codes -- File paths or URLs -- Code identifiers - -### Message Design - -1. **Keep messages concise** but informative -2. **Use parameters** for dynamic content instead of string concatenation -3. **Design for translation** - avoid culture-specific references -4. **Group related messages** using consistent key prefixes - -### Key Naming - -```rust -// Good: Hierarchical, descriptive -tinymist_l10n::t!("export.pdf.success", "PDF exported successfully") -tinymist_l10n::t!("export.pdf.error.permission", "Permission denied for PDF export") - -// Bad: Flat, unclear -tinymist_l10n::t!("msg1", "PDF exported successfully") -tinymist_l10n::t!("err", "Permission denied") -``` - -## Troubleshooting - -### Common Issues - -1. **Build errors after adding localization**: - - Ensure proper import of `tinymist_l10n` or `l10nMsg` - - Check for typos in macro/function calls - - Run `yarn build:l10n` to extract new messages - -2. **Missing translations**: - - Verify the key exists in the appropriate locale file - - Check if extraction was run after adding the message - - Ensure locale file syntax is valid TOML - -3. **Parameter substitution not working**: - - Verify parameter names match between code and translation - - Check for missing or extra parameters in translations - -### Testing Localization - -1. **Test message extraction**: -```bash -yarn build:l10n -``` - -2. **Verify locale files** contain your new messages - -3. **Test in different languages** by changing VSCode language settings - -## File Structure Reference - -``` -locales/ -├── README.md # Documentation -├── tinymist-vscode.toml # Manual VSCode translations -├── tinymist-vscode-rt.toml # Auto-extracted VSCode messages -└── tinymist-rt.toml # Auto-extracted Rust messages - -crates/ -├── tinymist-l10n/ # Localization library -└── */src/**/*.rs # Rust source files (use tinymist_l10n::t!) - -editors/vscode/ -├── src/l10n.ts # TypeScript l10n helper -└── src/**/*.ts # TypeScript source files (use l10nMsg) - -scripts/ -└── build-l10n.mjs # Message extraction script -``` - -## Advanced Usage - -### Conditional Messages - -```rust -let message = if is_error { - tinymist_l10n::t!("status.error", "Error occurred") -} else { - tinymist_l10n::t!("status.success", "Operation completed") -}; -``` - -### Pluralization - -Handle plurals with parameters: - -```rust -let message = tinymist_l10n::t!( - "files.count", - "{count} file(s) processed", - count = file_count -); -``` - -Translation: -```toml -[files.count] -en = "{count} file(s) processed" -zh = "已处理 {count} 个文件" -fr = "{count} fichier(s) traité(s)" -``` - -Remember to run `yarn build:l10n` after adding any new localized messages to code, and only edit translation files manually for languages other than English. \ No newline at end of file diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index c1992a912..000000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1,128 +0,0 @@ -This is a Rust+JavaScript repository. It builds: -- A Rust binary serves language features: - - `lsp`: Runs language server - - `dap`: Runs debug adapter - - `preview`: Runs preview server -- The JavaScript VS Code extension. -- The lua plugin for Neovim. - -It is primarily responsible for providing integrated typst language service to various editors like VS Code, Neovim, Emacs, and Zed. Please follow these guidelines when contributing: - -## Specialized Instructions - -- **Localization**: See [copilot-instructions-l10n.md](./copilot-instructions-l10n.md) for comprehensive guidance on adding, updating, and maintaining localization in the project. - -## Code Standards - -### Keep Good PR Title - -Determine a good PR prefix **only** by the PR description before work. Add a prefix to indicate what kind of release this pull request corresponds to. For reference, see https://www.conventionalcommits.org/ - -Available types: - - dev - - feat - - fix - - docs - - style - - refactor - - perf - - test - - build - - ci - - chore - - revert - -### Required Before Each Commit -- Run `yarn fmt` to format Rust/JavaScript files -- This will run formatters on all necessary files to maintain consistent style - -### Development Flow -- Build Server: `cargo build` -- Build VS Code Extension: `cd editors/vscode && yarn build` -- Full CI check: `cargo clippy --workspace --all-targets` -- Test Server: `cargo test --workspace -- --skip=e2e` - Note that, in the envoironment where network is not available (copilot or nix actions), we should also skip following tests: - ``` - completion::tests::test_pkgs - docs::package::tests::cetz - docs::package::tests::fletcher - docs::package::tests::tidy - docs::package::tests::touying - ``` - -## Repository Structure -- `crates/`: rust crates for the server and related functionality -- `editors/vscode/`: VS Code extension code -- `editors/neovim/`: Lua plugin for Neovim (canonical implementation - see [CONTRIBUTING.md](editors/neovim/CONTRIBUTING.md) and [Specification.md](editors/neovim/Specification.md)) -- `tools/editor-tools`: utility GUI tools for typst -- `tools/typst-preview-frontend`: Preview GUI for typst -- `docs/`: documentation for the project -- `locales/`: localization files for the entire project -- `tests/`: integration tests for the server and editors -- `syntaxes/`: textmate syntax definitions for typst - -## Key Guidelines -1. Follow Rust and JavaScript best practices and idiomatic patterns -2. Maintain existing code structure and organization -4. Write unit tests for new functionality. Use snapshot-based unit tests when possible. -5. Document public APIs and complex logic in code comments - -## Editor Integration Guidelines - -### Neovim Canonical Implementation - -The Neovim plugin in `editors/neovim/` serves as the **canonical implementation** of a Tinymist editor language client. When working on editor integrations: - -- **Reference Implementation**: Use the Neovim plugin as the reference for LSP client patterns, configuration handling, and event subscription mechanisms -- **Test Suite**: Refer to `editors/neovim/spec/` for comprehensive test coverage examples -- **Documentation**: See [editors/neovim/Specification.md](editors/neovim/Specification.md) for complete API and functionality documentation -- **Development Workflow**: Use `./bootstrap.sh editor` for interactive testing and `./bootstrap.sh test` for automated validation -- **Contributing**: Follow patterns established in [editors/neovim/CONTRIBUTING.md](editors/neovim/CONTRIBUTING.md) - -## Development Guidelines - -### `tools/editor-tools` - -The frontend-side and backend-side can be developed independently. For example, a data object passed from backend to frontend can be coded as `van.state` as follows: - -- Intermediate arguments: - - ```ts - const documentMetricsData = `:[[preview:DocumentMetrics]]:`; - const docMetrics = van.state( - documentMetricsData.startsWith(":") ? DOC_MOCK : JSON.parse(base64Decode(documentMetricsData)), - ); - ``` - -- Server-pushing arguments (e.g. `programTrace` in `tools/editor-tools/src/vscode.ts`): - - ```ts - export const programTrace = van.state(undefined /* init value */); - - export function setupVscodeChannel() { - if (vscodeAPI?.postMessage) { - // Handle messages sent from the extension to the webview - window.addEventListener("message", (event: any) => { - switch (event.data.type) { - case "traceData": { - programTrace.val = event.data.data; - break; - } - // other cases - } - }); - } - } - ``` - -- Tool request arguments (e.g. `requestSaveFontsExportConfigure` in `tools/editor-tools/src/vscode.ts`): - - ```ts - export function requestSaveFontsExportConfigure(data: fontsExportConfigure) { - if (vscodeAPI?.postMessage) { - vscodeAPI.postMessage({ type: "saveFontsExportConfigure", data }); - } - } - ``` - -`DOC_MOCK` is a mock data object for the frontend to display so that the frontend can be developed directly with `yarn dev`. diff --git a/.github/workflows/announce.yml b/.github/workflows/announce.yml deleted file mode 100644 index 861b7187b..000000000 --- a/.github/workflows/announce.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: tinymist::announce -on: - workflow_call: - inputs: - tag: - description: Release Tag - required: true - type: string - workflow_dispatch: - inputs: - tag: - description: Release Tag - required: true - type: string -permissions: - "contents": "write" - -env: - isNightly: ${{ ((!((!contains(inputs.tag, 'rc') && (endsWith(inputs.tag, '0') || endsWith(inputs.tag, '2') || endsWith(inputs.tag, '4') || endsWith(inputs.tag, '6') || endsWith(inputs.tag, '8')))))) }} - -jobs: - build: - runs-on: "ubuntu-22.04" - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - name: Install dist - # we specify bash to get pipefail; it guards against the `curl` command - # failing. otherwise `sh` won't catch that `curl` returned non-0 - shell: bash - run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/Myriad-Dreamin/cargo-dist/releases/download/v0.28.6-tinymist.3/cargo-dist-installer.sh | sh" - - name: Install parse changelog - uses: taiki-e/install-action@parse-changelog - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - cache: 'yarn' - - name: Install deps - run: yarn install - - id: announce - name: "Generate announcement" - run: | - yarn draft-release ${{ inputs.tag }} - echo "draft-release ran successfully" - - name: "Upload announcement changelog" - uses: actions/upload-artifact@v4 - with: - name: announcement-changelog.md - path: target/announcement-changelog.md - - name: "Upload announcement" - uses: actions/upload-artifact@v4 - with: - name: announcement-dist.md - path: target/announcement-dist.md - - name: "Upload announcement" - uses: actions/upload-artifact@v4 - with: - name: announcement.gen.md - path: target/announcement.gen.md - - name: Create GitHub Release - env: - PRERELEASE_FLAG: "${{ (fromJson(env.isNightly) && '--prerelease') || '' }}" - ANNOUNCEMENT_TITLE: "${{ steps.announce.outputs.tag }}" - RELEASE_COMMIT: "${{ github.sha }}" - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - echo "Creating release for ${{ steps.announce.outputs.tag }} with PRERELEASE_FLAG=$PRERELEASE_FLAG (isNightly=$isNightly)" - gh release create "${{ steps.announce.outputs.tag }}" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file target/announcement.gen.md --draft=true \ No newline at end of file diff --git a/.github/workflows/auto-tag.yml b/.github/workflows/auto-tag.yml deleted file mode 100644 index 6a3393d98..000000000 --- a/.github/workflows/auto-tag.yml +++ /dev/null @@ -1,151 +0,0 @@ -name: tinymist::auto_tag - -on: - push: - branches: - - main - -jobs: - auto-tag: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - token: ${{ secrets.REPO_TOKEN }} - fetch-depth: 0 - - - name: Get merged PR info - id: get-pr - run: | - COMMIT_SHA="${{ github.sha }}" - - PR_NUMBER=$(gh pr list --state merged --limit 50 --json number,mergeCommit \ - --jq ".[] | select(.mergeCommit.oid == \"$COMMIT_SHA\") | .number") - - if [ -n "$PR_NUMBER" ]; then - echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT - echo "Found merged PR: #$PR_NUMBER" - else - echo "pr_number=" >> $GITHUB_OUTPUT - echo "No merged PR found for this commit" - fi - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Check for tag directive in merged PR - if: steps.get-pr.outputs.pr_number != '' - id: check-tag - uses: actions/github-script@v7 - with: - script: | - const prNumber = '${{ steps.get-pr.outputs.pr_number }}'; - - if (!prNumber) { - console.log('No PR number found'); - core.setOutput('tag_found', 'false'); - return; - } - - try { - const { data: pr } = await github.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: parseInt(prNumber) - }); - - const prBody = pr.body || ''; - console.log('PR Body:', prBody); - - const tagRegex = /^\+tag\s+(v\d+\.\d+\.\d+(?:-[a-zA-Z0-9]+)?)/m; - - const match = prBody.match(tagRegex); - - if (match) { - const tagVersion = match[1]; - console.log('Found tag directive:', tagVersion); - - core.setOutput('tag_found', 'true'); - core.setOutput('tag_version', tagVersion); - } else { - console.log('No tag directive found in merged PR'); - core.setOutput('tag_found', 'false'); - } - } catch (error) { - console.error('Error fetching PR:', error); - core.setOutput('tag_found', 'false'); - } - - - name: Check if tag already exists - if: steps.check-tag.outputs.tag_found == 'true' - id: check-existing-tag - run: | - TAG="${{ steps.check-tag.outputs.tag_version }}" - - if git tag -l | grep -q "^$TAG$"; then - echo "tag_exists=true" >> $GITHUB_OUTPUT - echo "Tag $TAG already exists" - else - echo "tag_exists=false" >> $GITHUB_OUTPUT - echo "Tag $TAG does not exist, safe to create" - fi - - - name: Create tag - if: steps.check-tag.outputs.tag_found == 'true' && steps.check-existing-tag.outputs.tag_exists == 'false' - run: | - TAG="${{ steps.check-tag.outputs.tag_version }}" - PR_NUMBER="${{ steps.get-pr.outputs.pr_number }}" - - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - git tag -a "$TAG" -m "Auto-created tag $TAG from PR #$PR_NUMBER" - git push origin "$TAG" - - echo "Created and pushed tag: $TAG" - - - name: Comment on merged PR - if: steps.check-tag.outputs.tag_found == 'true' && steps.check-existing-tag.outputs.tag_exists == 'false' - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const tagVersion = '${{ steps.check-tag.outputs.tag_version }}'; - const prNumber = '${{ steps.get-pr.outputs.pr_number }}'; - - const comment = `**Tag Created Successfully** - - Tag \`${tagVersion}\` has been automatically created and pushed to the repository following the merge of this PR. - - You can view the tag here: https://github.com/${{ github.repository }}/releases/tag/${tagVersion}`; - - github.rest.issues.createComment({ - issue_number: parseInt(prNumber), - owner: context.repo.owner, - repo: context.repo.repo, - body: comment - }); - - - name: Handle tag creation error - if: steps.check-tag.outputs.tag_found == 'true' && steps.check-existing-tag.outputs.tag_exists == 'true' - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const tagVersion = '${{ steps.check-tag.outputs.tag_version }}'; - const prNumber = '${{ steps.get-pr.outputs.pr_number }}'; - const actionUrl = `${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}`; - - const comment = `**Tag Creation Failed** - - Could not create tag \`${tagVersion}\`. - - Please refer to [this action run](${actionUrl}) for more information.`; - - github.rest.issues.createComment({ - issue_number: parseInt(prNumber), - owner: context.repo.owner, - repo: context.repo.repo, - body: comment - }); diff --git a/.github/workflows/build-vsc-assets.yml b/.github/workflows/build-vsc-assets.yml deleted file mode 100644 index 9d447bf85..000000000 --- a/.github/workflows/build-vsc-assets.yml +++ /dev/null @@ -1,96 +0,0 @@ - -name: tinymist::build::vsc_assets -on: - workflow_call: - -env: - target: x86_64-unknown-linux-gnu - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - cache: 'yarn' - - name: Install deps - run: yarn install - - uses: actions-rust-lang/setup-rust-toolchain@v1 - - name: Download tinymist binary artifact - uses: actions/download-artifact@v4 - with: - name: artifacts-build-local-${{ env.target }} - path: prebuilts - - name: Unzip tinymist binary artifact (Windows) - run: 7z x -y -oprebuilts prebuilts/tinymist-${{ env.target }}.zip - if: contains(env.target, 'windows') - - name: Unzip tinymist binary artifact (Linux) - run: | - tar -xvf prebuilts/tinymist-${{ env.target }}.tar.gz -C prebuilts - mv prebuilts/tinymist-${{ env.target }}/tinymist prebuilts/tinymist - if: ${{ !contains(env.target, 'windows') }} - - name: Download font assets - # use fonts in stable releases - run: | - mkdir -p assets/fonts/ - curl -L https://github.com/Myriad-Dreamin/shiroa/releases/download/v0.1.2/font-assets.tar.gz | tar -xvz -C assets/fonts - curl -L https://github.com/Myriad-Dreamin/shiroa/releases/download/v0.1.0/charter-font-assets.tar.gz | tar -xvz -C assets/fonts - curl -L https://github.com/Myriad-Dreamin/shiroa/releases/download/v0.1.5/source-han-serif-font-assets.tar.gz | tar -xvz -C assets/fonts - - name: Download & install shiroa - run: | - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/Myriad-Dreamin/shiroa/releases/download/v0.3.1-rc3/shiroa-installer.sh | sh - - name: Build Book - run: | - shiroa build --font-path ./assets/typst-fonts/ --font-path ./assets/fonts/ --path-to-root /tinymist/ -w . docs/tinymist --mode=static-html - - name: Build PDF Documentation - run: | - prebuilts/tinymist compile --font-path assets/fonts --root . docs/tinymist/ebook.typ tinymist-docs.pdf - # todo: this is a bug - - name: Install PDF Documentation - run: | - mkdir -p editors/vscode/out/ contrib/html/editors/vscode/out/ - cp tinymist-docs.pdf editors/vscode/out/tinymist-docs.pdf - cp tinymist-docs.pdf contrib/html/editors/vscode/out/tinymist-docs.pdf - - name: Upload PDF Documentation - uses: actions/upload-artifact@v4 - with: - name: tinymist-docs.pdf - path: tinymist-docs.pdf - if-no-files-found: error - - - name: Build typst-preview vscode extension - run: | - yarn - yarn run compile - working-directory: ./contrib/typst-preview/editors/vscode - - name: Build tinymist vscode extension - run: | - yarn - yarn run compile - working-directory: ./editors/vscode - - - name: Pre-bundle tinymist vscode extension - uses: actions/upload-artifact@v4 - with: - name: vscode-artifacts-tinymist - path: editors/vscode/out - - name: Pre-bundle tinymist vscode extension (L10n) - uses: actions/upload-artifact@v4 - with: - name: vscode-artifacts-tinymist-l10n - path: | - editors/vscode/l10n/**/* - editors/vscode/package.nls.json - editors/vscode/package.nls.*.json - - name: Pre-bundle typst-preview vscode extension - uses: actions/upload-artifact@v4 - with: - name: vscode-artifacts-typst-preview - path: contrib/typst-preview/editors/vscode/out - diff --git a/.github/workflows/build-vscode-main.yml b/.github/workflows/build-vscode-main.yml deleted file mode 100644 index 20ea7ca70..000000000 --- a/.github/workflows/build-vscode-main.yml +++ /dev/null @@ -1,181 +0,0 @@ -name: tinymist::build::vscode::main -on: - workflow_call: - -jobs: - build: - strategy: - matrix: - include: - - os: windows-latest - rust-target: x86_64-pc-windows-msvc - platform: win32 - arch: x64 - regular_build: 'true' - - os: windows-latest - rust-target: aarch64-pc-windows-msvc - platform: win32 - arch: arm64 - - os: ubuntu-22.04 - rust-target: x86_64-unknown-linux-gnu - platform: linux - arch: x64 - regular_build: 'true' - - os: ubuntu-22.04 - rust-target: aarch64-unknown-linux-gnu - platform: linux - arch: arm64 - - os: ubuntu-22.04 - rust-target: arm-unknown-linux-gnueabihf - platform: linux - arch: armhf - - os: macos-14 - rust-target: x86_64-apple-darwin - platform: darwin - arch: x64 - - os: macos-14 - rust-target: aarch64-apple-darwin - platform: darwin - arch: arm64 - regular_build: 'true' - name: build (${{ matrix.platform }}-${{ matrix.arch }}) - runs-on: ${{ matrix.os }} - env: - target: ${{ matrix.platform }}-${{ matrix.arch }} - isRelease: ${{ (startsWith(github.ref, 'refs/tags/') && (!contains(github.ref, 'rc') && (endsWith(github.ref, '0') || endsWith(github.ref, '2') || endsWith(github.ref, '4') || endsWith(github.ref, '6') || endsWith(github.ref, '8')))) }} - isNightly: ${{ ((startsWith(github.ref, 'refs/tags/') && !((!contains(github.ref, 'rc') && (endsWith(github.ref, '0') || endsWith(github.ref, '2') || endsWith(github.ref, '4') || endsWith(github.ref, '6') || endsWith(github.ref, '8'))))) || (!startsWith(github.ref, 'refs/tags/') && matrix.regular_build == 'true')) }} - isTest: ${{ matrix.rust-target == 'x86_64-unknown-linux-gnu' || matrix.rust-target == 'x86_64-pc-windows-msvc' }} - isUniversal: ${{ matrix.rust-target == 'x86_64-unknown-linux-gnu' }} - steps: - - name: "Print Env" - run: | - echo "Running on ${{ matrix.os }}" - echo "Target: ${{ env.target }}" - echo "Is Release: ${{ fromJson(env.isRelease) }}" - echo "Is Nightly: ${{ fromJson(env.isNightly) }}" - echo "Is Test: ${{ fromJson(env.isTest) }}" - echo "Is Universal (No Server): ${{ fromJson(env.isUniversal) }}" - - uses: actions/checkout@v4 - with: - submodules: recursive - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 22 - cache: 'yarn' - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - - name: Install deps - run: yarn install - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - - - name: Download tinymist binary artifact - uses: actions/download-artifact@v4 - with: - name: artifacts-build-local-${{ matrix.rust-target }} - path: prebuilts - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - - name: Unzip tinymist binary artifact (Windows) - run: 7z x -y -oprebuilts prebuilts/tinymist-${{ matrix.rust-target }}.zip - if: matrix.platform == 'win32' && (fromJson(env.isRelease) || fromJson(env.isNightly)) - - name: Unzip tinymist binary artifact (Linux) - run: | - tar -xvf prebuilts/tinymist-${{ matrix.rust-target }}.tar.gz -C prebuilts - mv prebuilts/tinymist-${{ matrix.rust-target }}/tinymist prebuilts/tinymist - if: matrix.platform != 'win32' && (fromJson(env.isRelease) || fromJson(env.isNightly)) - - - name: Download VSC Assets - uses: actions/download-artifact@v4 - with: - name: vscode-artifacts-tinymist - path: editors/vscode/out - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - - name: Download VSC Assets (L10n) - uses: actions/download-artifact@v4 - with: - name: vscode-artifacts-tinymist-l10n - path: editors/vscode - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - - name: Download VSC Assets (Preview) - uses: actions/download-artifact@v4 - with: - name: vscode-artifacts-typst-preview - path: contrib/typst-preview/editors/vscode/out - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - - - name: Copy binary to output directory - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - run: | - cp "prebuilts/tinymist${{ ( matrix.platform == 'win32' ) && '.exe' || '' }}" "editors/vscode/out/" - cp "prebuilts/tinymist${{ ( matrix.platform == 'win32' ) && '.exe' || '' }}" "contrib/typst-preview/editors/vscode/out/" - cp "prebuilts/tinymist${{ ( matrix.platform == 'win32' ) && '.exe' || '' }}" "tinymist-${{ env.target }}${{ ( matrix.platform == 'win32' ) && '.exe' || '' }}" - - - name: Package typst-preview extension - if: fromJson(env.isRelease) - run: yarn run package -- --target ${{ env.target }} -o typst-preview-${{ env.target }}.vsix - working-directory: ./contrib/typst-preview/editors/vscode - - name: Package tinymist extension - if: fromJson(env.isRelease) - run: yarn run package -- --target ${{ env.target }} -o tinymist-${{ env.target }}.vsix - working-directory: ./editors/vscode - - name: Package typst-preview extension (Nightly) - if: fromJson(env.isNightly) - run: yarn run package -- --target ${{ env.target }} -o typst-preview-${{ env.target }}.vsix --pre-release - working-directory: ./contrib/typst-preview/editors/vscode - - name: Package tinymist extension (Nightly) - if: fromJson(env.isNightly) - run: yarn run package -- --target ${{ env.target }} -o tinymist-${{ env.target }}.vsix --pre-release - working-directory: ./editors/vscode - - - name: Upload binary artifact - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - uses: actions/upload-artifact@v4 - with: - name: tinymist-${{ env.target }} - path: tinymist-${{ env.target }}${{ fromJSON('["", ".exe"]')[matrix.platform == 'win32'] }} - - name: Upload typst-preview VSIX artifact - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - uses: actions/upload-artifact@v4 - with: - name: typst-preview-${{ env.target }}.vsix - path: contrib/typst-preview/editors/vscode/typst-preview-${{ env.target }}.vsix - - name: Upload VSIX artifact - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - uses: actions/upload-artifact@v4 - with: - name: tinymist-${{ env.target }}.vsix - path: editors/vscode/tinymist-${{ env.target }}.vsix - - - name: Test tinymist extension - uses: coactions/setup-xvfb@v1 - with: - run: yarn test - working-directory: ./editors/vscode - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) && fromJson(env.isTest) - - name: Upload Tinymist Testing log - if: ${{ always() && ((fromJson(env.isRelease) || fromJson(env.isNightly)) && fromJson(env.isTest))}} - uses: actions/upload-artifact@v4 - with: - name: tinymist-lsp-tests.${{ env.target }}.log - path: editors/vscode/e2e-workspaces/simple-docs/tinymist-lsp.log - - # The universal target doesn't bundle the binary. Users of that must install - # tinymist by themselves. - - name: Remove server binary - if: fromJson(env.isUniversal) - run: rm "editors/vscode/out/tinymist" - - name: Package extension (Universal) - if: fromJson(env.isRelease) && fromJson(env.isUniversal) - run: yarn run package -- -o tinymist-universal.vsix - working-directory: ./editors/vscode - - name: Package extension (Universal, Nightly) - if: fromJson(env.isNightly) && fromJson(env.isUniversal) - run: yarn run package -- -o tinymist-universal.vsix --pre-release - working-directory: ./editors/vscode - - name: Upload tinymist VSIX artifact (Universal) - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) && fromJson(env.isUniversal) - uses: actions/upload-artifact@v4 - with: - name: tinymist-universal.vsix - path: editors/vscode/tinymist-universal.vsix diff --git a/.github/workflows/build-vscode-others.yml b/.github/workflows/build-vscode-others.yml deleted file mode 100644 index 03a35c1e0..000000000 --- a/.github/workflows/build-vscode-others.yml +++ /dev/null @@ -1,188 +0,0 @@ - -name: tinymist::build::vscode::others -on: - workflow_call: - -env: - RUSTFLAGS: '-Dwarnings' - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc - -jobs: - build_alpine: - name: build extension (alpine-${{ matrix.arch }}) - runs-on: ${{ matrix.runner }} - if: startsWith(github.ref, 'refs/tags/') - container: - image: rust:alpine - volumes: - - /usr/local/cargo/registry:/usr/local/cargo/registry - - /opt:/opt:rw,rshared - - /opt:/__e/node20:ro,rshared - strategy: - matrix: - include: - - arch: x64 - target: alpine-x64 - RUST_TARGET: x86_64-unknown-linux-musl - runner: ubuntu-24.04 - - arch: arm64 - target: alpine-arm64 - RUST_TARGET: aarch64-unknown-linux-musl - runner: ubuntu-24.04-arm - env: - target: ${{ matrix.target }} - RUST_TARGET: ${{ matrix.RUST_TARGET }} - RUSTFLAGS: "-Dwarnings -C link-arg=-fuse-ld=lld -C target-feature=-crt-static" - isRelease: ${{ (startsWith(github.ref, 'refs/tags/') && (!contains(github.ref, 'rc') && (endsWith(github.ref, '0') || endsWith(github.ref, '2') || endsWith(github.ref, '4') || endsWith(github.ref, '6') || endsWith(github.ref, '8')))) }} - isNightly: ${{ ((startsWith(github.ref, 'refs/tags/') && !((!contains(github.ref, 'rc') && (endsWith(github.ref, '0') || endsWith(github.ref, '2') || endsWith(github.ref, '4') || endsWith(github.ref, '6') || endsWith(github.ref, '8')))))) }} - steps: - - name: Allow Linux musl containers on ARM64 runners - if: matrix.runner == 'ubuntu-24.04-arm' - run: | - sed -i "/^ID=/s/alpine/NotpineForGHA/" /etc/os-release - apk add nodejs --update-cache - mkdir /opt/bin - ln -s /usr/bin/node /opt/bin/node - - - name: Install dependencies - # bash is required by setup-rust-toolchain - run: apk add --no-cache git clang lld musl-dev nodejs-current npm yarn binutils bash - - name: Checkout repository - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - uses: actions-rust-lang/setup-rust-toolchain@v1 - - name: Install deps - run: yarn install - - name: Build typst-preview vscode extension - run: yarn run compile - working-directory: ./contrib/typst-preview/editors/vscode - - name: Build tinymist vscode extension - run: yarn run compile - working-directory: ./editors/vscode - - name: Build tinymist binary - run: | - cargo build --profile=gh-release --bin tinymist --target $RUST_TARGET - - name: Split debug symbols - run: | - cd target/$RUST_TARGET/gh-release - objcopy --compress-debug-sections --only-keep-debug "tinymist" "tinymist-${{ env.target }}.debug" - objcopy --strip-debug --add-gnu-debuglink="tinymist-${{ env.target }}.debug" "tinymist" - - name: Upload split debug symbols - uses: actions/upload-artifact@v4 - with: - name: tinymist-${{ env.target }}.debug - path: target/${{ env.RUST_TARGET }}/gh-release/tinymist-${{ env.target }}.debug - - name: Copy binary to output directory - run: | - mkdir -p editors/vscode/out - cp "target/${{ env.RUST_TARGET }}/gh-release/tinymist" "editors/vscode/out/" - cp "target/${{ env.RUST_TARGET }}/gh-release/tinymist" "contrib/typst-preview/editors/vscode/out/" - cp "target/${{ env.RUST_TARGET }}/gh-release/tinymist" "tinymist-${{ env.target }}" - - name: Upload binary artifact - uses: actions/upload-artifact@v4 - with: - name: tinymist-${{ env.target }} - path: tinymist-${{ env.target }} - - - name: Download PDF Documentation - uses: actions/download-artifact@v4 - with: - name: tinymist-docs.pdf - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - - name: Install PDF Documentation - run: | - mkdir -p editors/vscode/out/ - cp tinymist-docs.pdf editors/vscode/out/tinymist-docs.pdf - if: (fromJson(env.isRelease) || fromJson(env.isNightly)) - - - name: Package typst-preview extension - if: fromJson(env.isRelease) - run: yarn run package -- --target ${{ env.target }} -o typst-preview-${{ env.target }}.vsix - working-directory: ./contrib/typst-preview/editors/vscode - - name: Package extension - if: fromJson(env.isRelease) - run: yarn run package -- --target ${{ env.target }} -o tinymist-${{ env.target }}.vsix - working-directory: ./editors/vscode - - name: Package typst-preview extension (Nightly) - if: fromJson(env.isNightly) - run: yarn run package -- --target ${{ env.target }} -o typst-preview-${{ env.target }}.vsix --pre-release - working-directory: ./contrib/typst-preview/editors/vscode - - name: Package extension (Nightly) - if: fromJson(env.isNightly) - run: yarn run package -- --target ${{ env.target }} -o tinymist-${{ env.target }}.vsix --pre-release - working-directory: ./editors/vscode - - - name: Upload typst-preview VSIX artifact - uses: actions/upload-artifact@v4 - with: - name: typst-preview-${{ env.target }}.vsix - path: contrib/typst-preview/editors/vscode/typst-preview-${{ env.target }}.vsix - - name: Upload tinymist VSIX artifact - uses: actions/upload-artifact@v4 - with: - name: tinymist-${{ env.target }}.vsix - path: editors/vscode/tinymist-${{ env.target }}.vsix - - build_web: - name: build extension (web) - runs-on: ubuntu-latest - env: - target: web - RUST_TARGET: wasm32-unknown-unknown - isNightly: ${{ ((startsWith(github.ref, 'refs/tags/') && !((!contains(github.ref, 'rc') && (endsWith(github.ref, '0') || endsWith(github.ref, '2') || endsWith(github.ref, '4') || endsWith(github.ref, '6') || endsWith(github.ref, '8')))))) }} - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - cache: 'yarn' - - uses: actions-rust-lang/setup-rust-toolchain@v1 - - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: "v0.13.1" - - name: Install deps - run: yarn install - - name: Build tinymist library - run: yarn build:web - working-directory: . - - name: Pack tinymist npm library - run: | - npm pack > package-name - mv $(cat package-name) tinymist-${{ env.target }}.tar.gz - working-directory: ./crates/tinymist - - name: Upload tinymist npm library - uses: actions/upload-artifact@v4 - with: - name: tinymist-${{ env.target }}-npm - path: crates/tinymist/tinymist-${{ env.target }}.tar.gz - - - name: Download PDF Documentation - uses: actions/download-artifact@v4 - with: - name: tinymist-docs.pdf - - name: Install PDF Documentation - run: | - mkdir -p editors/vscode/out/ - cp tinymist-docs.pdf editors/vscode/out/tinymist-docs.pdf - - - name: Package extension - if: '!fromJson(env.isNightly)' - run: yarn run package -- --target ${{ env.target }} -o tinymist-${{ env.target }}.vsix - working-directory: ./editors/vscode - - name: Package extension (Nightly) - if: fromJson(env.isNightly) - run: yarn run package -- --target ${{ env.target }} -o tinymist-${{ env.target }}.vsix --pre-release - working-directory: ./editors/vscode - - - name: Upload tinymist VSIX artifact - uses: actions/upload-artifact@v4 - with: - name: tinymist-${{ env.target }}.vsix - path: editors/vscode/tinymist-${{ env.target }}.vsix diff --git a/.github/workflows/build-vscode.yml b/.github/workflows/build-vscode.yml deleted file mode 100644 index 26aad88ef..000000000 --- a/.github/workflows/build-vscode.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: tinymist::build::vscode -on: - workflow_call: - inputs: - plan: - description: 'A description of the plan input' - required: true # or false, depending on whether the input is mandatory - type: string # or other appropriate type like boolean, number, etc. - -env: - RUSTFLAGS: '-Dwarnings' - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc - -jobs: - build-vsc-assets: - uses: ./.github/workflows/build-vsc-assets.yml - - build-vscode-main: - needs: [build-vsc-assets] - uses: ./.github/workflows/build-vscode-main.yml - - build-vscode-others: - needs: [build-vsc-assets] - uses: ./.github/workflows/build-vscode-others.yml - - release: - needs: [build-vscode-main, build-vscode-others] # , announce - runs-on: ubuntu-latest - if: success() && startsWith(github.ref, 'refs/tags/') - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - uses: actions/download-artifact@v4 - with: - path: artifacts - pattern: '{tinymist,typst-preview}-*' - - name: Display structure of downloaded files - run: ls -R artifacts - - uses: ncipollo/release-action@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - artifacts: "artifacts/*/*" - allowUpdates: true - omitBodyDuringUpdate: true - omitDraftDuringUpdate: true - omitNameDuringUpdate: true - omitPrereleaseDuringUpdate: true - - publish: - needs: [build-vscode-main, build-vscode-others] # , announce - runs-on: ubuntu-latest - env: - isRelease: ${{ (startsWith(github.ref, 'refs/tags/') && (!contains(github.ref, 'rc') && (endsWith(github.ref, '0') || endsWith(github.ref, '2') || endsWith(github.ref, '4') || endsWith(github.ref, '6') || endsWith(github.ref, '8')))) }} - isNightly: ${{ ((startsWith(github.ref, 'refs/tags/') && !((!contains(github.ref, 'rc') && (endsWith(github.ref, '0') || endsWith(github.ref, '2') || endsWith(github.ref, '4') || endsWith(github.ref, '6') || endsWith(github.ref, '8')))))) }} - if: success() && startsWith(github.ref, 'refs/tags/') && !contains(github.ref, 'rc') - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - uses: actions/download-artifact@v4 - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - cache: 'yarn' - - name: Install deps - run: yarn install - - name: Deploy to VS Code Marketplace - if: fromJson(env.isRelease) - run: npx @vscode/vsce publish --packagePath $(find . -type f -iname 'tinymist-*.vsix') --skip-duplicate - env: - VSCE_PAT: ${{ secrets.VSCODE_MARKETPLACE_TOKEN }} - - name: Deploy to OpenVSX - if: fromJson(env.isRelease) - run: npx ovsx publish --packagePath $(find . -type f -iname 'tinymist-*.vsix') --skip-duplicate - env: - OVSX_PAT: ${{ secrets.OPENVSX_ACCESS_TOKEN }} - - name: Deploy to VS Code Marketplace (Nightly) - if: fromJson(env.isNightly) - run: npx @vscode/vsce publish --packagePath $(find . -type f -iname 'tinymist-*.vsix') --skip-duplicate --pre-release - env: - VSCE_PAT: ${{ secrets.VSCODE_MARKETPLACE_TOKEN }} - - name: Deploy to OpenVSX (Nightly) - if: fromJson(env.isNightly) - run: npx ovsx publish --packagePath $(find . -type f -iname 'tinymist-*.vsix') --skip-duplicate --pre-release - env: - OVSX_PAT: ${{ secrets.OPENVSX_ACCESS_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/ci-check-e2e.yml b/.github/workflows/ci-check-e2e.yml deleted file mode 100644 index 0adf4a395..000000000 --- a/.github/workflows/ci-check-e2e.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: tinymist::check-e2e -on: - workflow_call: - inputs: - plan: - description: 'A description of the plan input' - required: true # or false, depending on whether the input is mandatory - type: string # or other appropriate type like boolean, number, etc. - -env: - RUSTFLAGS: '-Dwarnings' - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc - -jobs: - checks-e2e: - strategy: - matrix: - include: - - os: windows-2022 - rust-target: x86_64-pc-windows-msvc - platform: win32 - arch: x64 - - os: windows-latest - rust-target: x86_64-pc-windows-msvc - platform: win32 - arch: x64 - - os: ubuntu-22.04 - rust-target: x86_64-unknown-linux-gnu - platform: linux - arch: x64 - - os: ubuntu-latest - rust-target: x86_64-unknown-linux-gnu - platform: linux - arch: x64 - - os: macos-latest - rust-target: aarch64-apple-darwin - platform: darwin - arch: arm64 - name: E2E Tests (${{ matrix.platform }}-${{ matrix.arch }} on ${{ matrix.os }}) - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - name: Download tinymist binary artifact - uses: actions/download-artifact@v4 - with: - name: artifacts-build-local-${{ matrix.rust-target }} - path: editors/vscode/out - - name: Unzip tinymist binary artifact (Windows) - run: 7z x -y -oeditors/vscode/out editors/vscode/out/tinymist-${{ matrix.rust-target }}.zip - if: matrix.platform == 'win32' - - name: Unzip tinymist binary artifact (Linux) - run: | - tar -xvf editors/vscode/out/tinymist-${{ matrix.rust-target }}.tar.gz -C editors/vscode/out - mv editors/vscode/out/tinymist-${{ matrix.rust-target }}/tinymist editors/vscode/out/tinymist - if: matrix.platform != 'win32' - - name: Test GLIBC - run: node ./scripts/test-glibc.mjs editors/vscode/out/tinymist - if: matrix.platform != 'win32' - - name: Test Tinymist (E2E) - run: cargo test -p tests -- e2e - - name: Upload Tinymist E2E Test Snapshot - if: always() - uses: actions/upload-artifact@v4 - with: - name: e2e-snapshot-${{ matrix.rust-target }}-${{ matrix.os }} - path: target/e2e diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 8e0db326c..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,138 +0,0 @@ -name: tinymist::ci -on: - push: - branches: - - main - - nightly - tags: - - "*" - pull_request: - types: [opened, synchronize] - branches: - - main - - nightly - workflow_dispatch: - -env: - RUSTFLAGS: '-Dwarnings' - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc - -jobs: - pre_build: - permissions: - actions: write - contents: read - name: Duplicate Actions Detection - runs-on: ubuntu-latest - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - cancel_others: "true" - - checks-linux: - name: Check Clippy, Formatting, Completion, Documentation, and Tests (Linux) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: typst-community/setup-typst@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - components: clippy, rustfmt - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - cache: 'yarn' - - name: Install deps - run: yarn install - - name: Check and build assets - run: | - yarn build:preview - yarn build:l10n - - run: cargo clippy --workspace --all-targets - - run: scripts/feature-testing.sh - - run: cargo fmt --check --all - - run: cargo doc --workspace --no-deps - - run: yarn build:typlite - - run: node ./scripts/link-docs.mjs --check - - name: Generate completions - run: | - mkdir -p completions/{zsh,bash,fish/vendor_completions.d,elvish/lib,nushell/vendor/autoload,powershell}/ - cargo run --bin tinymist -- completion zsh > completions/zsh/_tinymist - cargo run --bin tinymist -- completion bash > completions/bash/tinymist - cargo run --bin tinymist -- completion fish > completions/fish/vendor_completions.d/tinymist.fish - cargo run --bin tinymist -- completion elvish > completions/elvish/lib/tinymist.elv - cargo run --bin tinymist -- completion nushell > completions/nushell/vendor/autoload/tinymist.nu - cargo run --bin tinymist -- completion powershell > completions/powershell/tinymist.ps1 - tar -czvf tinymist-completions.tar.gz completions - - name: upload completions - uses: actions/upload-artifact@v4 - with: - name: tinymist-completion-scripts - path: tinymist-completions.tar.gz - - name: Test tinymist - run: cargo test --workspace -- --skip=e2e - - name: Test Lockfile (Prepare) - run: ./scripts/test-lock.sh - - name: Test Lockfile (Check) - run: cargo test --package tinymist --lib -- route::tests --show-output --ignored - - checks-windows: - name: Check Minimum Rust version and Tests (Windows) - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - toolchain: 1.89.0 # check-min-version - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - - name: Install deps - run: yarn install - - name: Check Rust Version - run: yarn check-msrv - - name: Check and build assets - run: | - yarn build:preview - yarn build:l10n - - run: cargo check --workspace - - name: Test tinymist - run: cargo test --workspace -- --skip=e2e - - prepare-build: - runs-on: "ubuntu-latest" - outputs: - tag: ${{ steps.tag.outputs.tag }} - steps: - - uses: actions/checkout@v4 - - id: tag # get the tag from package.json - run: - echo "tag=v$(jq -r '.version' editors/vscode/package.json)" >> $GITHUB_OUTPUT - - name: Show tag - run: echo "Tag is ${{ steps.tag.outputs.tag }}" - - announce: - needs: [prepare-build] - permissions: - contents: write - uses: ./.github/workflows/announce.yml - if: ${{ startsWith(github.ref, 'refs/tags/') }} - secrets: inherit - with: - tag: ${{ needs.prepare-build.outputs.tag }} - - build: - needs: [prepare-build] # , announce - permissions: - contents: write - uses: ./.github/workflows/release.yml - secrets: inherit - with: - tag: ${{ (startsWith(github.ref, 'refs/tags/') && needs.prepare-build.outputs.tag) || '' }} - targets: ${{ (!startsWith(github.ref, 'refs/tags/') && 'aarch64-apple-darwin,x86_64-pc-windows-msvc,x86_64-unknown-linux-gnu') || 'all' }} diff --git a/.github/workflows/detect-pr-tag.yml b/.github/workflows/detect-pr-tag.yml deleted file mode 100644 index 7a16f4b2e..000000000 --- a/.github/workflows/detect-pr-tag.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: tinymist::detect_pr_tag - -on: - pull_request: - types: [opened, edited] - branches: - - main - -jobs: - detect-tag: - runs-on: ubuntu-latest - - steps: - - name: Check tag in PR body - id: check-tag - uses: actions/github-script@v7 - with: - script: | - const prBody = context.payload.pull_request.body || ''; - console.log('PR Body:', prBody); - - const tagRegex = /^\+tag\s+(v\d+\.\d+\.\d+(?:-[a-zA-Z0-9]+)?)/m; - const match = prBody.match(tagRegex); - - if (match) { - const tagVersion = match[1]; - console.log('Found tag:', tagVersion); - - core.setOutput('tag_found', 'true'); - core.setOutput('tag_version', tagVersion); - } else { - console.log('No tag found in PR description'); - core.setOutput('tag_found', 'false'); - } - - - name: Comment on PR - if: steps.check-tag.outputs.tag_found == 'true' - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const tagVersion = '${{ steps.check-tag.outputs.tag_version }}'; - const comment = `**Tag Detection Notice** - - This PR contains a tag directive: \`+tag ${tagVersion}\` - - If this PR is merged, it will automatically create tag \`${tagVersion}\` on the main branch. - - Please ensure before merging: - - [ ] **Cargo.toml & Cargo.lock**: No \`git\` dependencies with \`branch\`, use \`tag\` or \`rev\` dependencies instead - - [ ] **Publish tokens**: Both \`VSCODE_MARKETPLACE_TOKEN\` and \`OPENVSX_ACCESS_TOKEN\` are valid and not expired - - [ ] **Version updates**: All version numbers in \`Cargo.toml\`, \`package.json\` and other files have been updated consistently - - [ ] **Changelog**: \`editors/vscode/CHANGELOG.md\` has been updated with correct format - - [ ] **tinymist-assets**: If needed, the crate has been published and version updated in \`Cargo.toml\` - ` - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: comment - }); diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml deleted file mode 100644 index 713fc3c65..000000000 --- a/.github/workflows/gh-pages.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: tinymist::gh_pages -on: - push: - branches: - - main - workflow_dispatch: - -permissions: - pages: write - id-token: write - contents: read - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: 'pages' - cancel-in-progress: false - -jobs: - build-gh-pages: - runs-on: ubuntu-latest - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - steps: - - name: Checkout - uses: actions/checkout@v3 - - run: git submodule update --init --recursive - - name: Make directories - run: | - if [ ! -d "${XDG_DATA_HOME:-$HOME/.local/share}" ]; then - echo "Creating data directory: ${XDG_DATA_HOME:-$HOME/.local/share}" - mkdir -p ${XDG_DATA_HOME:-$HOME/.local/share} - else - echo "Data directory already exists: ${XDG_DATA_HOME:-$HOME/.local/share}" - fi - if [ ! -d "${XDG_CACHE_HOME:-$HOME/.cache}" ]; then - echo "Creating cache directory: ${XDG_CACHE_HOME:-$HOME/.cache}" - mkdir -p ${XDG_CACHE_HOME:-$HOME/.cache} - else - echo "Cache directory already exists: ${XDG_CACHE_HOME:-$HOME/.cache}" - fi - - name: Download font assets - # use fonts in stable releases - run: | - mkdir -p assets/fonts/ - curl -L https://github.com/Myriad-Dreamin/shiroa/releases/download/v0.1.2/font-assets.tar.gz | tar -xvz -C assets/fonts - curl -L https://github.com/Myriad-Dreamin/shiroa/releases/download/v0.1.0/charter-font-assets.tar.gz | tar -xvz -C assets/fonts - curl -L https://github.com/Myriad-Dreamin/shiroa/releases/download/v0.1.5/source-han-serif-font-assets.tar.gz | tar -xvz -C assets/fonts - - name: Download & install shiroa - run: | - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/Myriad-Dreamin/shiroa/releases/download/v0.3.1-rc3/shiroa-installer.sh | sh - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - cache: 'yarn' - - name: Install deps - run: yarn install - - name: Build Preview Html - run: | - yarn build:preview - - name: Build Book - run: | - shiroa build --font-path ./assets/typst-fonts/ --font-path ./assets/fonts/ --path-to-root /tinymist/ -w . docs/tinymist --mode=static-html - - name: Build Cargo Docs - run: | - cargo doc --workspace --no-deps - cp -r target/doc dist/tinymist/rs - - name: Setup Pages - uses: actions/configure-pages@v5 - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - # Upload `/github-pages` sub directory - path: './dist/tinymist' - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/.github/workflows/lint-pr-title.yml b/.github/workflows/lint-pr-title.yml deleted file mode 100644 index 81e71fa7a..000000000 --- a/.github/workflows/lint-pr-title.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: tinymist::lint_pr_title -on: - pull_request: - types: [opened, edited, synchronize] - -permissions: - pull-requests: write - -jobs: - main: - name: Validate PR title - runs-on: ubuntu-latest - steps: - - uses: amannn/action-semantic-pull-request@v5 - id: lint_pr_title - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - # Configure which types are allowed (newline-delimited). - # Default: https://github.com/commitizen/conventional-commit-types - # extraType: dev: internal development - types: | - dev - feat - fix - docs - style - refactor - perf - test - build - ci - chore - revert - ignoreLabels: | - bot - ignore-semantic-pull-request - - uses: marocchino/sticky-pull-request-comment@v2 - # When the previous steps fails, the workflow would stop. By adding this - # condition you can continue the execution with the populated error message. - if: always() && (steps.lint_pr_title.outputs.error_message != null) - with: - header: pr-title-lint-error - message: | - Hey there and thank you for opening this pull request! 👋🏼 - - We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted. - - Details: - - ``` - ${{ steps.lint_pr_title.outputs.error_message }} - ``` - # Delete a previous comment when the issue has been resolved - - if: ${{ steps.lint_pr_title.outputs.error_message == null }} - uses: marocchino/sticky-pull-request-comment@v2 - with: - header: pr-title-lint-error - delete: true \ No newline at end of file diff --git a/.github/workflows/release-asset-crate.yml b/.github/workflows/release-asset-crate.yml deleted file mode 100644 index e2382cf8a..000000000 --- a/.github/workflows/release-asset-crate.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: tinymist::assets::publish -on: - workflow_dispatch: - -env: - RUSTFLAGS: '-Dwarnings' - -jobs: - - publish-crates: - name: build - runs-on: ubuntu-22.04 - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - cache: false - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 24 - cache: 'yarn' - - name: Install llvm - run: | - sudo apt-get update - sudo apt-get install llvm - - name: Install deps - run: yarn install - - name: Check and build assets - run: | - yarn build:preview - yarn build:l10n - - name: Publish crates - run: | - cargo publish --allow-dirty --no-verify -p tinymist-assets || true - - name: Verifies crate health (Optional) - run: | - cargo publish --allow-dirty --dry-run -p tinymist-assets diff --git a/.github/workflows/release-crates.yml b/.github/workflows/release-crates.yml deleted file mode 100644 index 8ae80d9b6..000000000 --- a/.github/workflows/release-crates.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: tinymist::crates::publish -on: - push: - tags: - - "*" - workflow_dispatch: - -env: - RUSTFLAGS: '-Dwarnings' - -jobs: - - publish-crates: - name: build - runs-on: ubuntu-latest - env: - CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - # https://github.com/dtolnay/rust-toolchain/issues/133 - # https://github.com/rust-lang/rustup/issues/3635 - # Only needed if your action will run two or more rust - # commands concurrently, otherwise rustup will lazily - # install your rust-toolchain.toml when needed: - - name: 'Install from rust-toolchain.toml' - run: rustup show - - name: Install llvm - run: | - sudo apt-get update - sudo apt-get install llvm - - name: Publish crates - run: | - cargo publish --no-verify -p typst-shim || true - cargo publish --no-verify -p tinymist-derive || true - cargo publish --no-verify -p tinymist-l10n || true - cargo publish --no-verify -p tinymist-std || true - cargo publish --no-verify -p sync-ls || true - cargo publish --no-verify -p tinymist-package || true - cargo publish --no-verify -p tinymist-vfs || true - cargo publish --no-verify -p tinymist-world || true - cargo publish --no-verify -p tinymist-analysis || true - cargo publish --no-verify -p tinymist-task || true - cargo publish --no-verify -p tinymist-project || true - cargo publish --no-verify -p typlite || true - cargo publish --no-verify -p crityp || true - - cargo publish --no-verify -p tinymist-debug || true - cargo publish --no-verify -p tinymist-lint || true - cargo publish --no-verify -p tinymist-query || true - cargo publish --no-verify -p tinymist-render || true - cargo publish --no-verify -p tinymist-preview || true - cargo publish --no-verify -p tinymist || true - cargo publish --no-verify -p tinymist-cli || true - - name: Verifies crate health (Optional) - run: | - cargo publish --dry-run -p typst-shim - cargo publish --dry-run -p tinymist-derive - cargo publish --dry-run -p tinymist-l10n - cargo publish --dry-run -p tinymist-std - cargo publish --dry-run -p sync-ls - cargo publish --dry-run -p tinymist-vfs - cargo publish --dry-run -p tinymist-package - cargo publish --dry-run -p tinymist-world - cargo publish --dry-run -p tinymist-task --features no-content-hint - cargo publish --dry-run -p tinymist-project --features no-content-hint - cargo publish --dry-run -p typlite - cargo publish --dry-run -p crityp - # needs patched typst - # cargo publish --dry-run -p tinymist-analysis - \ No newline at end of file diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml deleted file mode 100644 index 86ab63070..000000000 --- a/.github/workflows/release-nightly.yml +++ /dev/null @@ -1,350 +0,0 @@ -name: Nightly Release - -on: - schedule: - - cron: '0 0 * * *' - - cron: '0 23 * * *' - workflow_dispatch: - inputs: - release_type: - description: 'Release type' - required: true - default: 'nightly' - type: choice - options: - - nightly - - canary - -jobs: - check-and-release: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: nightly - token: ${{ secrets.REPO_TOKEN }} - fetch-depth: 0 - - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 22 - cache: 'yarn' - - name: Install deps - run: yarn install - - - name: Setup Git - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - - - name: Determine release type - id: release_type - run: | - if [[ "${{ github.event_name }}" == "schedule" ]]; then - if [[ "${{ github.event.schedule }}" == "0 0 * * *" ]]; then - echo "release_type=nightly" >> $GITHUB_ENV - else - echo "release_type=canary" >> $GITHUB_ENV - fi - else - echo "release_type=${{ github.event.inputs.release_type }}" >> $GITHUB_ENV - fi - - - name: Check for updates - id: check_updates - run: | - echo "Checking for updates in dependency repositories..." - - # Get current revs using script - eval "$(node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . get-current-revs)" - - # Get latest revs - latest_typst_rev=$(curl -s "https://api.github.com/repos/ParaN3xus/typst/commits/nightly" | jq -r '.sha') - latest_typst_content_hint_rev=$(curl -s "https://api.github.com/repos/ParaN3xus/typst/commits/nightly-content-hint" | jq -r '.sha') - latest_reflexo_rev=$(curl -s "https://api.github.com/repos/ParaN3xus/typst.ts/commits/nightly" | jq -r '.sha') - latest_typstyle_rev=$(curl -s "https://api.github.com/repos/ParaN3xus/typstyle/commits/nightly" | jq -r '.sha') - latest_typst_ansi_hl_rev=$(curl -s "https://api.github.com/repos/ParaN3xus/typst-ansi-hl/commits/nightly" | jq -r '.sha') - - echo "Current revs: typst=$current_typst_rev, typst.ts=$current_reflexo_rev, typstyle=$current_typstyle_rev, hl=$current_typst_ansi_hl_rev" - echo "Latest revs: typst=$latest_typst_rev, typst.ts=$latest_reflexo_rev, typstyle=$latest_typstyle_rev, hl=$latest_typst_ansi_hl_rev" - - # Check for updates - need_update=false - if [[ "$current_typst_rev" != "$latest_typst_rev" ]] || [[ -z "$current_typst_rev" ]]; then - echo "Typst needs update" - need_update=true - fi - if [[ "$current_reflexo_rev" != "$latest_reflexo_rev" ]] || [[ -z "$current_reflexo_rev" ]]; then - echo "Typst.ts needs update" - need_update=true - fi - if [[ "$current_typstyle_rev" != "$latest_typstyle_rev" ]] || [[ -z "$current_typstyle_rev" ]]; then - echo "Typstyle needs update" - need_update=true - fi - if [[ "$current_typst_ansi_hl_rev" != "$latest_typst_ansi_hl_rev" ]] || [[ -z "$current_typst_ansi_hl_rev" ]]; then - echo "Typst-ansi-hl needs update" - need_update=true - fi - - current_version=$(grep '^version = ' Cargo.toml | head -1 | cut -d'"' -f2) - echo "current_version=$current_version" >> $GITHUB_ENV - - # Updates can only be performed when releasing an RC. - # When an RC has been released and there are no subsequent updates, - # this indicates that the RC release was successful. Only at this - # point will the nightly release be published. - - need_release=false - if [ "$release_type" = "nightly" ]; then - if [ "$need_update" = "false" ] && echo "$current_version" | grep -q -- '-rc[0-9]\+$'; then - echo "RC version detected with no updates needed, nightly release condition met" - need_release=true - else - echo "Nightly release condition not met (requires stable RC version)" - fi - elif [ "$release_type" = "canary" ]; then - if [ "$need_update" = "true" ]; then - echo "Code updates detected, canary release condition met" - need_release=true - else - echo "No code updates, skipping canary release" - fi - fi - - echo "Final decision: need_release=$need_release" - - echo "need_release=$need_release" >> $GITHUB_OUTPUT - echo "latest_typst_rev=$latest_typst_rev" >> $GITHUB_ENV - echo "latest_typst_content_hint_rev=$latest_typst_content_hint_rev" >> $GITHUB_ENV - - - name: Calculate new version - id: version - if: steps.check_updates.outputs.need_release == 'true' - run: | - echo "Current version: $current_version" - echo "Release type: $release_type" - - new_version=$(node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . calculate-version "$current_version" "$release_type") - - echo "New version: $new_version" - echo "new_version=$new_version" >> $GITHUB_ENV - - - uses: actions-rust-lang/setup-rust-toolchain@v1 - if: steps.check_updates.outputs.need_release == 'true' - - - name: Get typst information - id: typst_info - if: steps.check_updates.outputs.need_release == 'true' - run: | - # Clone typst repository - git clone --depth 50 --single-branch --branch nightly-content-hint \ - --filter=blob:limit=1k https://github.com/ParaN3xus/typst.git /tmp/typst - cd /tmp/typst - git checkout nightly-content-hint - - # Get version - typst_version=$(grep '^version = ' Cargo.toml | head -1 | cut -d'"' -f2) - - typst_assets_rev=$(grep 'typst-assets.*git' Cargo.toml | grep 'rev = ' | cut -d'"' -f4) - - echo "typst_version=$typst_version" >> $GITHUB_ENV - echo "typst_assets_rev=$typst_assets_rev" >> $GITHUB_ENV - - # Get base commit - git remote add upstream https://github.com/typst/typst.git && git fetch upstream main --prune - typst_base_commit=$(git merge-base HEAD upstream/main 2>/dev/null) - typst_base_msg=$(git --no-pager log --format="%s" -1 $typst_base_commit) - echo "typst_base_commit=$typst_base_commit" >> $GITHUB_ENV - echo "typst_base_msg=$typst_base_msg" >> $GITHUB_ENV - - - name: Update typst dependencies in tinymist - if: steps.check_updates.outputs.need_release == 'true' - run: | - node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-typst-deps \ - "$typst_version" \ - "$typst_assets_rev" - - revs_json=$(cat <> $GITHUB_ENV - - - name: Update typst.ts - if: steps.check_updates.outputs.need_release == 'true' - run: | - # Clone typst.ts - git clone https://${{ secrets.NIGHTLY_REPO_TOKEN }}@github.com/ParaN3xus/typst.ts.git /tmp/typst.ts - cd /tmp/typst.ts - git checkout nightly - - new_version="$new_version" - - # node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-world-crates "$new_version" - - # Update typst dependencies - node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-typst-deps \ - "$typst_version" \ - "$typst_assets_rev" - - # Update patches - revs_json=$(cat <> $GITHUB_ENV - - - name: Update typstyle - if: steps.check_updates.outputs.need_release == 'true' - run: | - # Clone typstyle - git clone https://${{ secrets.NIGHTLY_REPO_TOKEN }}@github.com/ParaN3xus/typstyle.git /tmp/typstyle - cd /tmp/typstyle - git checkout nightly - - # node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-world-crates "$new_version" - node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-typst-deps \ - "$typst_version" \ - "$typst_assets_rev" - - # Update patches - revs_json=$(cat <> $GITHUB_ENV - - - name: Update typst-ansi-hl - if: steps.check_updates.outputs.need_release == 'true' - run: | - # Clone typst-ansi-hl - git clone https://${{ secrets.NIGHTLY_REPO_TOKEN }}@github.com/ParaN3xus/typst-ansi-hl.git /tmp/typst-ansi-hl - cd /tmp/typst-ansi-hl - git checkout nightly - - node $GITHUB_WORKSPACE/scripts/nightly-utils.mjs . update-typst-deps \ - "$typst_version" \ - "$typst_assets_rev" - - # Update patches - revs_json=$(cat <> $GITHUB_ENV - - - name: Update tinymist patches and versions - if: steps.check_updates.outputs.need_release == 'true' - run: | - # Update patch revisions using script - revs_json=$(cat < plan-dist-manifest.json - echo "dist ran successfully" - cat plan-dist-manifest.json - echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" - - name: "Upload dist-manifest.json" - uses: actions/upload-artifact@v4 - with: - name: artifacts-plan-dist-manifest - path: plan-dist-manifest.json - - # Build and packages all the platform-specific things - build-local-artifacts: - name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) - # Let the initial task tell us to not run (currently very blunt) - needs: - - plan - if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || (fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') || (inputs.targets == 'all' || contains(inputs.targets, join(fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.targets, '')))) || inputs.tag == 'dry-run' }} - strategy: - fail-fast: false - # Target platforms/runners are computed by dist in create-release. - # Each member of the matrix has the following arguments: - # - # - runner: the github runner - # - dist-args: cli flags to pass to dist - # - install-dist: expression to run to install dist on the runner - # - # Typically there will be: - # - 1 "global" task that builds universal installers - # - N "local" tasks that build each platform's binaries and platform-specific installers - matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} - runs-on: ${{ matrix.runner }} - container: ${{ matrix.container && matrix.container.image || null }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json - steps: - - name: enable windows longpaths - run: | - git config --global core.longpaths true - - uses: actions/checkout@v4 - with: - persist-credentials: false - submodules: recursive - - name: Install Rust non-interactively if not already installed - if: ${{ matrix.container }} - run: | - if ! command -v cargo > /dev/null 2>&1; then - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - echo "$HOME/.cargo/bin" >> $GITHUB_PATH - fi - - uses: swatinem/rust-cache@v2 - with: - key: ${{ join(matrix.targets, '-') }} - cache-provider: ${{ matrix.cache_provider }} - - name: Install dist - run: ${{ matrix.install_dist.run }} - # Get the dist-manifest - - name: Fetch local artifacts - uses: actions/download-artifact@v4 - with: - pattern: artifacts-* - path: target/distrib/ - merge-multiple: true - - name: Install dependencies - run: | - ${{ matrix.packages_install }} - - name: Build artifacts - run: | - # Actually do builds and make zips and whatnot - dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json - echo "dist ran successfully" - - id: cargo-dist - name: Post-build - # We force bash here just because github makes it really hard to get values up - # to "real" actions without writing to env-vars, and writing to env-vars has - # inconsistent syntax between shell and powershell. - shell: bash - run: | - # Parse out what we just built and upload it to scratch storage - echo "paths<> "$GITHUB_OUTPUT" - dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT" - echo "EOF" >> "$GITHUB_OUTPUT" - - cp dist-manifest.json "$BUILD_MANIFEST_NAME" - - name: "Upload artifacts" - uses: actions/upload-artifact@v4 - with: - name: artifacts-build-local-${{ join(matrix.targets, '_') }} - path: | - ${{ steps.cargo-dist.outputs.paths }} - ${{ env.BUILD_MANIFEST_NAME }} - - # Build and package all the platform-agnostic(ish) things - build-global-artifacts: - needs: - - plan - - build-local-artifacts - runs-on: "ubuntu-22.04" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - submodules: recursive - - name: Install cached dist - uses: actions/download-artifact@v4 - with: - name: cargo-dist-cache - path: ~/.cargo/bin/ - - run: chmod +x ~/.cargo/bin/dist - # Get all the local artifacts for the global tasks to use (for e.g. checksums) - - name: Fetch local artifacts - uses: actions/download-artifact@v4 - with: - pattern: artifacts-* - path: target/distrib/ - merge-multiple: true - - id: cargo-dist - shell: bash - run: | - dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json - echo "dist ran successfully" - - # Parse out what we just built and upload it to scratch storage - echo "paths<> "$GITHUB_OUTPUT" - jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" - echo "EOF" >> "$GITHUB_OUTPUT" - - cp dist-manifest.json "$BUILD_MANIFEST_NAME" - - name: "Upload artifacts" - uses: actions/upload-artifact@v4 - with: - name: artifacts-build-global - path: | - ${{ steps.cargo-dist.outputs.paths }} - ${{ env.BUILD_MANIFEST_NAME }} - - custom-build-vscode: - needs: - - plan - - build-local-artifacts - uses: ./.github/workflows/build-vscode.yml - with: - plan: ${{ needs.plan.outputs.val }} - secrets: inherit + pre_build: permissions: - "contents": "write" - - custom-ci-check-e2e: - needs: - - plan - - build-local-artifacts - uses: ./.github/workflows/ci-check-e2e.yml - with: - plan: ${{ needs.plan.outputs.val }} - secrets: inherit - # Determines if we should publish/announce - host: - needs: - - plan - - build-local-artifacts - - build-global-artifacts - - custom-build-vscode - - custom-ci-check-e2e - # Only run if we're "publishing", and only if local and global didn't fail (skipped is fine) - if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-build-vscode.result == 'skipped' || needs.custom-build-vscode.result == 'success') && (needs.custom-ci-check-e2e.result == 'skipped' || needs.custom-ci-check-e2e.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - runs-on: "ubuntu-22.04" + actions: write + contents: read + name: Duplicate Actions Detection + runs-on: ubuntu-latest outputs: - val: ${{ steps.host.outputs.manifest }} + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + cancel_others: "true" + build: + strategy: + matrix: + include: + - os: windows-latest + rust-target: x86_64-pc-windows-msvc + platform: win32 + arch: x64 + regular_build: 'true' + - os: windows-latest + rust-target: aarch64-pc-windows-msvc + platform: win32 + arch: arm64 + - os: ubuntu-20.04 + rust-target: x86_64-unknown-linux-gnu + platform: linux + arch: x64 + regular_build: 'true' + - os: ubuntu-20.04 + rust-target: aarch64-unknown-linux-gnu + platform: linux + arch: arm64 + - os: ubuntu-20.04 + rust-target: arm-unknown-linux-gnueabihf + platform: linux + arch: armhf + - os: macos-11 + rust-target: x86_64-apple-darwin + platform: darwin + arch: x64 + - os: macos-11 + rust-target: aarch64-apple-darwin + platform: darwin + arch: arm64 + regular_build: 'true' + name: build (${{ matrix.platform }}-${{ matrix.arch }}) + runs-on: ${{ matrix.os }} + env: + target: ${{ matrix.platform }}-${{ matrix.arch }} steps: - uses: actions/checkout@v4 with: - persist-credentials: false submodules: recursive - - name: Install cached dist - uses: actions/download-artifact@v4 + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - uses: actions/checkout@v4 with: - name: cargo-dist-cache - path: ~/.cargo/bin/ - - run: chmod +x ~/.cargo/bin/dist - # Fetch artifacts from scratch-storage - - name: Fetch artifacts - uses: actions/download-artifact@v4 + repository: Enter-tainer/typst-preview + path: external/typst-preview + ref: preview-disable-frontend + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.4 + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - name: Install Node.js + uses: actions/setup-node@v4 with: - pattern: artifacts-* - path: target/distrib/ - merge-multiple: true - - id: host - shell: bash + node-version: 16 + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - name: Hack typst-preview run: | - dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json - echo "artifacts uploaded and released successfully" - cat dist-manifest.json - echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" - - name: "Upload dist-manifest.json" + mv src/main.rs src/main.rsx + working-directory: ./external/typst-preview + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - name: Build typst-dom + run: | + yarn + yarn build + working-directory: ./external/typst-preview/addons/typst-dom + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - name: Build frontend + run: yarn + working-directory: ./external/typst-preview/addons/frontend + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - name: Build typst-preview + run: | + yarn + yarn run compile + working-directory: ./external/typst-preview/addons/vscode + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - name: Install deps + run: yarn install + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - name: Build vscode extension + run: | + yarn + yarn run compile + working-directory: ./editors/vscode + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - name: rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.rust-target }} + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + - name: Install llvm + if: matrix.platform == 'linux' && (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + run: | + sudo apt-get update + sudo apt-get install llvm + - name: Install AArch64 target toolchain + if: matrix.rust-target == 'aarch64-unknown-linux-gnu' && (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + run: | + sudo apt-get update + sudo apt-get install gcc-aarch64-linux-gnu + - name: Install ARM target toolchain + if: matrix.rust-target == 'arm-unknown-linux-gnueabihf' && (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + run: | + sudo apt-get update + sudo apt-get install gcc-arm-linux-gnueabihf + - name: Build tinymist binary + shell: pwsh + run: | + cargo build --release -p tinymist --target ${{ matrix.rust-target }} + if: startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true' + - name: Rename debug symbols for windows + if: matrix.platform == 'win32' && (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + run: | + cd target/${{ matrix.rust-target }}/release + cp tinymist.pdb tinymist-${{ env.target }}.pdb + - name: Upload split debug symbols for windows + if: matrix.platform == 'win32' && (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') uses: actions/upload-artifact@v4 with: - # Overwrite the previous copy - name: artifacts-dist-manifest - path: dist-manifest.json - # Create a GitHub Release while uploading all files to it - - name: "Download GitHub Artifacts" - uses: actions/download-artifact@v4 + name: tinymist-${{ env.target }}.pdb + path: target/${{ matrix.rust-target }}/release/tinymist-${{ env.target }}.pdb + - name: Split debug symbols for linux + if: matrix.platform == 'linux' && (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + run: | + cd target/${{ matrix.rust-target }}/release + llvm-objcopy --compress-debug-sections --only-keep-debug "tinymist" "tinymist-${{ env.target }}.debug" + llvm-objcopy --strip-debug --add-gnu-debuglink="tinymist-${{ env.target }}.debug" "tinymist" + - name: Upload split debug symbols for linux + if: matrix.platform == 'linux' && (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + uses: actions/upload-artifact@v4 with: - pattern: artifacts-* - path: artifacts - merge-multiple: true - - name: Cleanup + name: tinymist-${{ env.target }}.debug + path: target/${{ matrix.rust-target }}/release/tinymist-${{ env.target }}.debug + compression-level: 0 + - name: Collect debug symbols for mac + if: matrix.platform == 'darwin' && (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') run: | - # Remove the granular manifests - rm -f artifacts/*-dist-manifest.json - - name: Create GitHub Release - env: - PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" - RELEASE_COMMIT: "${{ github.sha }}" + dsymutil -f "target/${{ matrix.rust-target }}/release/tinymist" + mv "target/${{ matrix.rust-target }}/release/tinymist.dwarf" "target/${{ matrix.rust-target }}/release/tinymist-${{ env.target }}.dwarf" + - name: Upload split debug symbols for mac + if: matrix.platform == 'darwin' && (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + uses: actions/upload-artifact@v4 + with: + name: tinymist-${{ env.target }}.dwarf + path: target/${{ matrix.rust-target }}/release/tinymist-${{ env.target }}.dwarf + - name: Copy binary to output directory + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + shell: pwsh run: | - # If we're editing a release in place, we need to upload things ahead of time - gh release upload "${{ needs.plan.outputs.tag }}" artifacts/* + cp "target/${{ matrix.rust-target }}/release/tinymist$(If ('${{ matrix.platform }}' -eq 'win32') { '.exe' } else { '' } )" "editors/vscode/out/" + cp "target/${{ matrix.rust-target }}/release/tinymist$(If ('${{ matrix.platform }}' -eq 'win32') { '.exe' } else { '' } )" "tinymist-${{ env.target }}$(If ('${{ matrix.platform }}' -eq 'win32') { '.exe' } else { '' } )" + - name: Upload binary artifact + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + uses: actions/upload-artifact@v4 + with: + name: tinymist-${{ env.target }} + path: tinymist-${{ env.target }}${{ fromJSON('["", ".exe"]')[matrix.platform == 'win32'] }} + - name: Package extension + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + shell: pwsh + run: yarn run package -- --target ${{ env.target }} -o tinymist-${{ env.target }}.vsix + working-directory: ./editors/vscode + - name: Upload VSIX artifact + if: (startsWith(github.ref, 'refs/tags/') || matrix.regular_build == 'true') + uses: actions/upload-artifact@v4 + with: + name: tinymist-${{ env.target }}.vsix + path: editors/vscode/tinymist-${{ env.target }}.vsix - gh release edit "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --draft=false - - announce: - needs: - - plan - - host - # use "always() && ..." to allow us to wait for all publish jobs while - # still allowing individual publish jobs to skip themselves (for prereleases). - # "host" however must run to completion, no skipping allowed! - if: ${{ always() && needs.host.result == 'success' }} - runs-on: "ubuntu-22.04" + build_alpine: + name: build (x86_64-unknown-linux-musl) + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + container: + image: rust:alpine + volumes: + - /usr/local/cargo/registry:/usr/local/cargo/registry env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + target: alpine-x64 + RUST_TARGET: x86_64-unknown-linux-musl + RUSTFLAGS: "-C link-arg=-fuse-ld=lld -C target-feature=-crt-static" + steps: + - name: Install dependencies + run: apk add --no-cache git clang lld musl-dev nodejs npm yarn binutils + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.4 + - uses: actions/checkout@v4 + with: + repository: Enter-tainer/typst-preview + path: external/typst-preview + ref: preview-disable-frontend + - name: Hack typst-preview + run: | + mv src/main.rs src/main.rsx + working-directory: ./external/typst-preview + - name: Build typst-dom + run: | + yarn + yarn build + working-directory: ./external/typst-preview/addons/typst-dom + - name: Build frontend + run: yarn + working-directory: ./external/typst-preview/addons/frontend + - name: Build typst-preview + run: | + yarn + yarn run compile + working-directory: ./external/typst-preview/addons/vscode + - name: Install deps + run: yarn install + - name: Build vscode extension + run: | + yarn + yarn run compile + working-directory: ./editors/vscode + - name: Build tinymist binary + run: | + cargo build --release -p tinymist --target $RUST_TARGET + mkdir -p editors/vscode/out + - name: Split debug symbols + run: | + cd target/$RUST_TARGET/release + objcopy --compress-debug-sections --only-keep-debug "tinymist" "tinymist-${{ env.target }}.debug" + objcopy --strip-debug --add-gnu-debuglink="tinymist-${{ env.target }}.debug" "tinymist" + - name: Upload split debug symbols + uses: actions/upload-artifact@v4 + with: + name: tinymist-${{ env.target }}.debug + path: target/${{ env.RUST_TARGET }}/release/tinymist-${{ env.target }}.debug + - name: Copy binary to output directory + run: | + cp "target/${{ env.RUST_TARGET }}/release/tinymist" "editors/vscode/out/" + cp "target/${{ env.RUST_TARGET }}/release/tinymist" "tinymist-${{ env.target }}" + - name: Upload binary artifact + uses: actions/upload-artifact@v4 + with: + name: tinymist-${{ env.target }} + path: tinymist-${{ env.target }} + - name: Package extension + run: yarn run package -- --target ${{ env.target }} -o tinymist-${{ env.target }}.vsix + working-directory: ./editors/vscode + - name: Upload VSIX artifact + uses: actions/upload-artifact@v4 + with: + name: tinymist-${{ env.target }}.vsix + path: editors/vscode/tinymist-${{ env.target }}.vsix + + release: + runs-on: ubuntu-latest + needs: [build, build_alpine] + if: success() && startsWith(github.ref, 'refs/tags/') + permissions: + contents: write steps: - uses: actions/checkout@v4 with: - persist-credentials: false submodules: recursive + - uses: actions/download-artifact@v4 + with: + path: artifacts + - name: Display structure of downloaded files + run: ls -R artifacts + - uses: ncipollo/release-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + artifacts: "artifacts/*/*" + allowUpdates: true + omitBodyDuringUpdate: true + omitDraftDuringUpdate: true + omitNameDuringUpdate: true + omitPrereleaseDuringUpdate: true + + publish: + runs-on: ubuntu-latest + needs: [build] + if: success() && startsWith(github.ref, 'refs/tags/') + steps: + - uses: actions/download-artifact@v4 + + - name: Deploy to VS Code Marketplace + run: npx vsce publish --packagePath $(find . -type f -iname '*.vsix') + env: + VSCE_PAT: ${{ secrets.VSCODE_MARKETPLACE_TOKEN }} + + - name: Deploy to OpenVSX + run: npx ovsx publish --packagePath $(find . -type f -iname '*.vsix') + env: + OVSX_PAT: ${{ secrets.OPENVSX_ACCESS_TOKEN }} diff --git a/.gitignore b/.gitignore index f278aa659..09c338f6a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,11 +5,6 @@ result* .envrc node_modules/ /local/ -editors/vscode/out/ -editors/lapce/out/ -/external/typst-preview -/dist - -*.pdf -.vscode/*.code-workspace -refs/ \ No newline at end of file +/editors/vscode/out/ +/editors/lapce/out/ +/external/typst-preview \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index cb2468c19..a86429976 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,25 +1,10 @@ -.DS_Store .git/** .github/** .vscode/** assets/** src/** target/** -dist/** -icons/ -node_modules/ -editors/vscode/test-dist/ -editors/vscode/out/ -editors/vscode/.vscode-test/** *.toml *.txt *.lock *.md - -.env -.env.* - -# Ignore files for PNPM, NPM and YARN -pnpm-lock.yaml -package-lock.json -yarn.lock diff --git a/.prettierrc.cjs b/.prettierrc.cjs deleted file mode 100644 index 72ac3891a..000000000 --- a/.prettierrc.cjs +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - // same options as rust-analyzer, otherwise defaults from prettier - printWidth: 100, - tabWidth: 2, - useTabs: false, - semi: true, - singleQuote: false, - quoteProps: "as-needed", - trailingComma: "all", - bracketSpacing: true, - arrowParens: "always", - singleAttributePerLine: false, -}; diff --git a/.vscode/launch.json b/.vscode/launch.json index cff53a1bd..e555bf262 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -15,21 +15,7 @@ "preLaunchTask": "VS Code Extension Prelaunch" }, { - "name": "Run Extension [Web]", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentKind=web", - "--extensionDevelopmentPath=${workspaceFolder}/editors/vscode" - ], - "outFiles": [ - "${workspaceFolder}/editors/vscode/out/**/*.js" - ], - "preLaunchTask": "VS Code Extension Prelaunch [Web]" - }, - { - "name": "Run Extension [Release]", + "name": "Run Extension [Jaeger]", "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", @@ -39,96 +25,7 @@ "outFiles": [ "${workspaceFolder}/editors/vscode/out/**/*.js" ], - "preLaunchTask": "VS Code Extension Prelaunch [Release]" - }, - { - "name": "Run Extension [Typst Preview]", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}/contrib/typst-preview/editors/vscode" - ], - "outFiles": [ - "${workspaceFolder}/contrib/typst-preview/editors/vscode/out/**/*.js" - ], - "preLaunchTask": "VS Code Extension Prelaunch Preview" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in executable 'tinymist'", - "cargo": { - "args": [ - "test", - "--no-run", - "--bin=tinymist", - "--package=tinymist" - ], - "filter": { - "name": "tinymist", - "kind": "bin" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in library 'tinymist-query'", - "cargo": { - "args": [ - "test", - "--no-run", - "--lib", - "--package=tinymist-query" - ], - "filter": { - "name": "tinymist-query", - "kind": "lib" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in library 'tinymist-render'", - "cargo": { - "args": [ - "test", - "--no-run", - "--lib", - "--package=tinymist-render" - ], - "filter": { - "name": "tinymist-render", - "kind": "lib" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug integration test 'tinymist-e2e-tests'", - "cargo": { - "args": [ - "test", - "--no-run", - "--test=tinymist-e2e-tests", - "--package=tests" - ], - "filter": { - "name": "tinymist-e2e-tests", - "kind": "test" - } - }, - "args": [], - "cwd": "${workspaceFolder}" + "preLaunchTask": "VS Code Extension Prelaunch [Jaeger]" } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index d702ca1df..997a3f50d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,8 +2,5 @@ "eslint.format.enable": true, "eslint.workingDirectories": [ "editors/vscode" - ], - "tinymist.fontPaths": [ - "assets/fonts" - ], + ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 8f37acb2c..e7387fe5b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -3,30 +3,10 @@ "tasks": [ { "label": "VS Code Extension Prelaunch", - "type": "npm", - "script": "prelaunch:vscode", - "group": "build", - }, - { - "label": "VS Code Extension Prelaunch [Web]", - "type": "npm", - "script": "build:web", - "group": "build" - }, - { - "label": "VS Code Extension Prelaunch Preview", - "dependsOn": [ - "Compile Typst Preview Extension", - "Copy Debug LSP Binary to Typst Preview Extension" - ], - "dependsOrder": "sequence", - }, - { - "label": "VS Code Extension Prelaunch [Release]", "dependsOn": [ "Compile VS Code Extension", - "Build Release LSP Binary", - "Copy Release LSP Binary to VS Code Extension" + "Build Debug LSP Binary", + "Copy Debug LSP Binary to VS Code Extension" ], "dependsOrder": "sequence", }, @@ -36,10 +16,7 @@ "Compile VS Code Extension", "Build Release LSP Binary", "Copy Release LSP Binary to VS Code Extension", - "Generate VS Code Extension Bundle", - "Compile Typst Preview Extension", - "Copy Release LSP Binary to Typst Preview Extension", - "Generate Typst Preview Extension Bundle" + "Generate VS Code Extension Bundle" ], "dependsOrder": "sequence", }, @@ -50,13 +27,6 @@ "path": "editors/vscode", "group": "build", }, - { - "label": "Compile VS Code Extension [Web]", - "type": "npm", - "script": "compile:web", - "path": "editors/vscode", - "group": "build", - }, { "label": "Generate VS Code Extension Bundle", "type": "npm", @@ -65,33 +35,50 @@ "group": "build", }, { - "label": "Compile Typst Preview Extension", - "type": "npm", - "script": "compile", - "path": "contrib/typst-preview/editors/vscode", - "group": "build", - }, - { - "label": "Generate Typst Preview Extension Bundle", - "type": "npm", - "script": "package", - "path": "contrib/typst-preview/editors/vscode", - "group": "build", + "label": "Build Debug LSP Binary", + "type": "cargo", + "command": "build", + "args": [ "--bin", "tinymist" ], + "problemMatcher": [ + "$rustc" + ], + "group": "build" }, { "label": "Build Release LSP Binary", "type": "cargo", "command": "build", - "args": [ - "--release", - "--bin", - "tinymist" - ], + "args": [ "--release", "--bin", "tinymist" ], "problemMatcher": [ "$rustc" ], "group": "build" }, + { + "label": "Copy Debug LSP Binary to VS Code Extension", + "type": "shell", + "windows": { + "command": "cp", + "args": [ + "${workspaceFolder}\\target\\debug\\tinymist.exe", + "${workspaceFolder}\\editors\\vscode\\out\\" + ] + }, + "linux": { + "command": "cp", + "args": [ + "${workspaceFolder}/target/debug/tinymist", + "${workspaceFolder}/editors/vscode/out/" + ] + }, + "osx": { + "command": "cp", + "args": [ + "${workspaceFolder}/target/debug/tinymist", + "${workspaceFolder}/editors/vscode/out/" + ] + } + }, { "label": "Copy Release LSP Binary to VS Code Extension", "type": "shell", @@ -116,56 +103,6 @@ "${workspaceFolder}/editors/vscode/out/" ] } - }, - { - "label": "Copy Debug LSP Binary to Typst Preview Extension", - "type": "shell", - "windows": { - "command": "cp", - "args": [ - "${workspaceFolder}\\target\\debug\\tinymist.exe", - "${workspaceFolder}\\contrib\\typst-preview\\editors\\vscode\\out\\" - ] - }, - "linux": { - "command": "cp", - "args": [ - "${workspaceFolder}/target/debug/tinymist", - "${workspaceFolder}/contrib/typst-preview/editors/vscode/out/" - ] - }, - "osx": { - "command": "cp", - "args": [ - "${workspaceFolder}/target/debug/tinymist", - "${workspaceFolder}/contrib/typst-preview/editors/vscode/out/" - ] - } - }, - { - "label": "Copy Release LSP Binary to Typst Preview Extension", - "type": "shell", - "windows": { - "command": "cp", - "args": [ - "${workspaceFolder}\\target\\release\\tinymist.exe", - "${workspaceFolder}\\contrib\\typst-preview\\editors\\vscode\\out\\" - ] - }, - "linux": { - "command": "cp", - "args": [ - "${workspaceFolder}/target/release/tinymist", - "${workspaceFolder}/contrib/typst-preview/editors/vscode/out/" - ] - }, - "osx": { - "command": "cp", - "args": [ - "${workspaceFolder}/target/release/tinymist", - "${workspaceFolder}/contrib/typst-preview/editors/vscode/out/" - ] - } } ] } diff --git a/.vscode/tinymist.code-workspace.tmpl.json b/.vscode/tinymist.code-workspace.tmpl.json deleted file mode 100644 index 1e8171d55..000000000 --- a/.vscode/tinymist.code-workspace.tmpl.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$schema": "vscode://schemas/workspaceConfig", - "folders": [ - { - "path": ".." - } - ], - "settings": { - "tinymist.fontPaths": [ - "assets/fonts" - ], - "[javascript]":{ - "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode", - }, - "[json]": { - "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "eslint.format.enable": true, - "eslint.workingDirectories": [ - "editors/vscode" - ], - "rust-analyzer.check.command": "clippy", - "rust-analyzer.rustfmt.extraArgs": ["--config=wrap_comments=true"], - "files.watcherExclude": { - "**/target": true - }, - }, - "extensions": { - "recommendations": [ - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", - "myriad-dreamin.tinymist", - ] - }, -} diff --git a/.zed/settings.json b/.zed/settings.json deleted file mode 100644 index 5a5ca963d..000000000 --- a/.zed/settings.json +++ /dev/null @@ -1,22 +0,0 @@ -// Folder-specific settings -// -// For a full list of overridable settings, and general information on folder-specific settings, -// see the documentation: https://zed.dev/docs/configuring-zed#settings-files -{ - "lsp": { - "rust-analyzer": { - "initialization_options": { - "check": { - "command": "clippy" - } - } - }, - "tinymist": { - "initialization_options": { - "exportPdf": "onSave", - "fontPaths": ["assets/fonts"], - "outputPath": "$root/target/typst/$dir/$name" - } - } - } -} diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 5ef631b94..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -[CHANGELOG.md](./editors/vscode/CHANGELOG.md) \ No newline at end of file diff --git a/CHANGELOG/CHANGELOG-2024.md b/CHANGELOG/CHANGELOG-2024.md deleted file mode 100644 index ba2f235ea..000000000 --- a/CHANGELOG/CHANGELOG-2024.md +++ /dev/null @@ -1,1255 +0,0 @@ -# Change Log - -All notable changes to the "tinymist" extension will be documented in this file. - -Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. - -The changelog lines unspecified with authors are all written by the @Myriad-Dreamin. - -## v0.12.14 - [2024-12-25] - -*We now use [cargo-dist](https://github.com/axodotdev/cargo-dist) to build, attest, and release binaries. The package publishers should prefer to use these binaries and validate them along with checksum.* If you have any problems with changes, please report them to [GitHub Issues](https://github.com/Myriad-Dreamin/tinymist/issues). - -These following suffixes are used for VS Code (or VSCodium) extensions: `win32-x64`, `win32-arm64`, `linux-x64`, `linux-arm64`, `linux-armhf`, `darwin-x64`, `darwin-arm64`, `alpine-x64`, `alpine-arm64`, and `web`. The rest are used for other editors (e.g. Neovim). - -We also start to release VS Code extension targeting universal platform. The universal target only doesn't bundle the binary. This is suitable for other platforms like RISC-V (riscv64) or LoongArch (loong64). Users of that must install tinymist by themselves. Note it introduces risk to use unaligned version of the extension and the binary, but we can mitigate it in future. - -* Bumped typstyle to v0.12.13 by @Enter-tainer in https://github.com/Myriad-Dreamin/tinymist/pull/1047 - * This version fixes a bugs that removes comments in math equations in some cases. For details, see https://enter-tainer.github.io/typstyle/changelog/#v01213---2024-12-21 -* Bumped typstfmt to v0.12.1 in https://github.com/Myriad-Dreamin/tinymist/pull/1056 -* Bumped typst-ansi-hl to v0.3.0 in https://github.com/Myriad-Dreamin/tinymist/pull/1057 - -### Editor - -* (Fix) Excluded dollar characters from matched typst language words in https://github.com/Myriad-Dreamin/tinymist/pull/1054 - -### Code Analysis - -* (Fix) Determining `name_started` in signature constructors in https://github.com/Myriad-Dreamin/tinymist/pull/1038 -* Inferring types of show rule transformers in https://github.com/Myriad-Dreamin/tinymist/pull/1045 - -### Completion - -* (Fix) Corrected wrong offset on Neovim for some postfix snippets by @Eric-Song-Nop in https://github.com/Myriad-Dreamin/tinymist/pull/966 -* (Fix) Improved various cases about completing field accesses in https://github.com/Myriad-Dreamin/tinymist/pull/1019, https://github.com/Myriad-Dreamin/tinymist/pull/1020, https://github.com/Myriad-Dreamin/tinymist/pull/1039, and https://github.com/Myriad-Dreamin/tinymist/pull/1040 -* (Fix) Adjusting offset from start when completing labels in https://github.com/Myriad-Dreamin/tinymist/pull/1051 -* Made and using new field access classifier for completion in https://github.com/Myriad-Dreamin/tinymist/pull/1035 -* Completing fields by type checking in https://github.com/Myriad-Dreamin/tinymist/pull/1041 and https://github.com/Myriad-Dreamin/tinymist/pull/1050 -* Completing tidy-style doc comment by @Eric-Song-Nop in https://github.com/Myriad-Dreamin/tinymist/pull/1029 - -### Misc -* Building binaries for riscv64-linux-musl, loongarch64-linux-{musl,gnu} in https://github.com/Myriad-Dreamin/tinymist/pull/1009, https://github.com/Myriad-Dreamin/tinymist/pull/1014, and https://github.com/Myriad-Dreamin/tinymist/pull/1012 -* Building vscode extension targeting other (universal) platforms in https://github.com/Myriad-Dreamin/tinymist/pull/10091059 - -**Full Changelog**: https://github.com/Myriad-Dreamin/tinymist/compare/v0.12.12...v0.12.14 - -## v0.12.12 - [2024-12-15] - -* Bumped typstyle from v0.12.6 to v0.12.12 by @Enter-tainer in https://github.com/Myriad-Dreamin/tinymist/pull/987 and https://github.com/Myriad-Dreamin/tinymist/pull/1010 - * This version includes massive update on comment formatting and binary operator chain formatting. For details, see https://enter-tainer.github.io/typstyle/changelog/#v01211---2024-12-16 - -### Editor - -* Configuring word separator and pattern specific for typst in https://github.com/Myriad-Dreamin/tinymist/pull/990 and https://github.com/Myriad-Dreamin/tinymist/pull/1002 - * Previously `some-ident` is split to `|some-|ident|` from left to right or `|some|-ident|` from right to left. Now VS Code identifies it as a single word. -* Checking affiliated column for a hidden typst source document in https://github.com/Myriad-Dreamin/tinymist/pull/1003 - -### Preview - -* (Fix) Rewrote some code for compatibility to some old chromium core by @Parsifa1 in https://github.com/Myriad-Dreamin/tinymist/pull/995 -* Jumping to nearest position in preview from cursor by @Eric-Song-Nop and @Myriad-Dreamin in https://github.com/Myriad-Dreamin/tinymist/pull/997 and https://github.com/Myriad-Dreamin/tinymist/pull/1004 - * Partially fix [issues/626](https://github.com/Myriad-Dreamin/tinymist/issues/626), it doesn't quite work but this is the first step. - -### Code Analysis -* (Fix) Simplified types of variables for hover tooltip by @Eric-Song-Nop and @Myriad-Dreamin in https://github.com/Myriad-Dreamin/tinymist/pull/959 -* (Fix) Corrected two wrong usages of `analyze_import` which prevents code analysis across modules in https://github.com/Myriad-Dreamin/tinymist/pull/967 -* Checking type of labels with tolerating syntax error in https://github.com/Myriad-Dreamin/tinymist/pull/975 - * For example, the non-closed label in `#cite(", "Nathan Varner"] -version = "0.14.6-rc1" -edition = "2024" +version = "0.10.3" +edition = "2021" readme = "README.md" license = "Apache-2.0" homepage = "https://github.com/Myriad-Dreamin/tinymist" repository = "https://github.com/Myriad-Dreamin/tinymist" -# also change in ci.yml -rust-version = "1.89" +rust-version = "1.74" [workspace] resolver = "2" -members = ["benches/*", "crates/*", "tests"] +members = ["crates/*"] [workspace.dependencies] -# Basic Infra +once_cell = "1" anyhow = "1" -itertools = "0.13" -paste = "1.0" -cfg-if = "1.0" -strum = { version = "0.27.2", features = ["derive"] } -quote = "1" -syn = "2" -triomphe = { version = "0.1.10", default-features = false, features = ["std"] } -# Asynchoronous and Multi-threading -async-trait = "0.1.89" +fxhash = "0.2.1" +ecow = "0.2.1" +comemo = "0.4" +ena = "0.14.2" futures = "0.3" -rayon = "1.11.0" -tokio = { version = "1.48.0", features = ["macros"] } -tokio-util = { version = "0.7.16", features = ["compat"] } - -# System -battery = "0.7.8" -temp-env = "0.3.6" -open = { version = "5.3.2" } +regex = "1.10.3" +itertools = "0.12.1" +lazy_static = "1.4.0" +env_logger = "0.11.3" +log = "0.4.21" +strum = { version = "0.26.2", features = ["derive"] } +async-trait = "0.1.77" parking_lot = "0.12.1" walkdir = "2" -chrono = { version = "0.4", default-features = false } -time = "0.3" -dirs = "6" -fontdb = { version = "0.23", default-features = false } -notify = "6" -path-clean = "1.0.1" -windows-sys = "0.61.2" -tempfile = "3.19.1" -same-file = "1.0.6" -libc = "0.2.155" -core-foundation = { version = "0.10.0", features = ["mac_os_10_7_support"] } -half = "=2.6.0" - -# Web -js-sys = "^0.3" -wasm-bindgen = "^0.2" -wasm-bindgen-futures = "^0.4" -wasm-bindgen-test = "0.3.45" -web-sys = "^0.3" -web-time = { version = "1.1.0" } -console_error_panic_hook = { version = "0.1.7" } - -# Networking -hyper = { version = "1", features = ["full"] } -hyper-util = { version = "0.1.17", features = ["tokio"] } -hyper-tungstenite = "0.19.0" -reqwest = { version = "^0.12", default-features = false, features = [ - "rustls-tls", - "blocking", - "multipart", -] } -http-body-util = "0.1.3" - -# Algorithms -base64 = "0.22" -regex = "1.12.2" - -# Cryptography and data processing -rustc-hash = { version = "2", features = ["std"] } -siphasher = "1" -fxhash = "0.2.1" -sha2 = "0.10.9" -nohash-hasher = "0.2.0" -fastrand = "2.3.0" - -# Data Structures -bitvec = "1" -comemo = "0.5.0" -# We need to freeze the version of the crate, as the raw-api feature is considered unstable -dashmap = { version = "=5.5.3", features = ["raw-api"] } -ecow = "0.2.6" -ena = "0.14.3" -hashbrown = { version = "0.14", features = [ - "inline-more", -], default-features = false } -indexmap = "2.12.0" -rpds = "1" - -# Data/Text Format and Processing -biblatex = "0.11" -bytes = "1" -cmark-writer = { version = "0.9.0", features = [ - "gfm", -], path = "crates/cmark-writer" } -docx-rs = { version = "0.4.18-rc19", git = "https://github.com/Myriad-Dreamin/docx-rs", default-features = false, rev = "db49a729f68dbdb9e8e91857fbb1c3d414209871" } -hayagriva = "0.9.1" -hex = "0.4.3" -flate2 = "1" -# typst can only support these formats. -image = { version = "0.25.5", default-features = false, features = [ - "png", - "jpeg", - "gif", -] } -pathdiff = "0.2" -percent-encoding = "2" -rust_iso639 = "0.0.3" -rust_iso3166 = "0.1.4" -resvg = { version = "0.45" } -rkyv = "0.7.42" -semver = "1" -serde = { version = "1", features = ["derive"] } -serde_json = "1" -serde_repr = "0.1" -serde_with = { version = "3.6", features = ["base64"] } -serde_yaml = "0.9" -serde-wasm-bindgen = "^0.6" -tar = "0.4" +indexmap = "2.1.0" +paste = "1.0" toml = { version = "0.8", default-features = false, features = [ "parse", "display", ] } -ttf-parser = "0.25.0" -unicode-script = "0.5" -unscanny = "0.1" -yaml-rust2 = "0.9" - -# Logging codespan-reporting = "0.11" -env_logger = "0.11.3" -log = "0.4" -# Typst -reflexo = { version = "=0.7.0-rc2", default-features = false, features = [ - "flat-vector", -] } -reflexo-typst = { version = "=0.7.0-rc2", default-features = false } -reflexo-vec2svg = { version = "=0.7.0-rc2" } +typst = "0.11.0" +typst-ide = "0.11.0" +typst-pdf = "0.11.0" +typst-assets = { git = "https://github.com/typst/typst-assets", rev = "4d1211a" } +typst-ts-core = { version = "0.4.2-rc8" } +typst-ts-compiler = { version = "0.4.2-rc8" } +typst-preview = { git = "https://github.com/Enter-tainer/typst-preview", rev = "18630ebda22339109ef675a885787f4fc8731ba8" } -typst = "0.14.2" -typst-html = "0.14.2" -typst-library = "0.14.2" -typst-macros = "0.14.2" -typst-timing = "0.14.2" -typst-svg = "0.14.2" -typst-render = "0.14.2" -typst-pdf = "0.14.2" -typst-syntax = "0.14.2" -typst-eval = "0.14.2" -typst-assets = "0.14.2" -typstfmt = { version = "0", git = "https://github.com/Myriad-Dreamin/typstfmt", tag = "v0.13.1" } -typst-ansi-hl = "0.4.0" -typstyle-core = { version = "=0.14.0", default-features = false } - -# LSP -crossbeam-channel = "0.5.15" +lsp-server = "0.7.6" lsp-types = { version = "=0.95.0", features = ["proposed"] } -dapts = "0.0.6" +crossbeam-channel = "0.5.12" -# CLI -clap = { version = "4.5", features = ["derive", "env", "unicode"] } -clap_builder = { version = "4.5", features = ["string"] } -clap_complete = "4.5" -clap_complete_fig = "4.5" -clap_complete_nushell = "4.5.3" -clap_mangen = { version = "0.2.22" } -vergen = { version = "8.3.1", features = [ +clap = { version = "4.4", features = ["derive", "env", "unicode", "wrap_help"] } +clap_builder = { version = "4", features = ["string"] } +clap_complete = "4.4" +clap_complete_fig = "4.4" +clap_mangen = { version = "0.2.15" } +vergen = { version = "8.2.5", features = [ "build", "cargo", "git", "gitcl", "rustc", ] } +tokio = { version = "1.36.0", features = [ + "macros", + "rt-multi-thread", + "io-std", +] } +tokio-util = "0.7.10" +serde = { version = "1", features = ["derive"] } +serde_json = "1" -# Testing -dhat = "0.3.3" -divan = "0.1.21" -insta = { version = "1.43", features = ["glob", "filters"] } -insta-cmd = "0.6.0" - - -# Our Own Crates -tinymist-assets = { version = "=0.14.6-rc1" } - -tinymist-derive = { path = "./crates/tinymist-derive/", version = "0.14.6-rc2" } -tinymist-l10n = { path = "./crates/tinymist-l10n/", version = "0.14.6-rc2" } -tinymist-package = { path = "./crates/tinymist-package/", version = "0.14.6-rc2" } -tinymist-std = { path = "./crates/tinymist-std/", version = "0.14.6-rc2", default-features = false } -tinymist-vfs = { path = "./crates/tinymist-vfs/", version = "0.14.6-rc2", default-features = false } -tinymist-world = { path = "./crates/tinymist-world/", version = "0.14.6-rc2", default-features = false } -tinymist-project = { path = "./crates/tinymist-project/", version = "0.14.6-rc2" } -tinymist-task = { path = "./crates/tinymist-task/", version = "0.14.6-rc2" } -typst-shim = { path = "./crates/typst-shim", version = "0.14.6-rc2" } - -tinymist-tests = { path = "./crates/tinymist-tests/" } - -sync-ls = { path = "./crates/sync-lsp", version = "0.14.6-rc1" } -tinymist = { path = "./crates/tinymist/", version = "0.14.6-rc1", default-features = false } -tinymist-analysis = { path = "./crates/tinymist-analysis/", version = "0.14.6-rc1" } -tinymist-cli = { path = "./crates/tinymist-cli/", version = "0.14.6-rc1" } -tinymist-debug = { path = "./crates/tinymist-debug/", version = "0.14.6-rc1" } -tinymist-lint = { path = "./crates/tinymist-lint/", version = "0.14.6-rc1" } -tinymist-query = { path = "./crates/tinymist-query/", version = "0.14.6-rc1" } -tinymist-render = { path = "./crates/tinymist-render/", version = "0.14.6-rc1" } -tinymist-preview = { path = "./crates/typst-preview", version = "0.14.6-rc1" } -typlite = { path = "./crates/typlite", version = "0.14.6-rc1", default-features = false } +divan = "0.1.14" +insta = { vesrion = "1.36", features = ["glob"] } [profile.dev.package.insta] opt-level = 3 @@ -223,115 +83,43 @@ opt-level = 3 opt-level = 3 [profile.release] -# lto = true # Enable link-time optimization -codegen-units = 1 # Reduce number of codegen units to increase optimizations -panic = "abort" # Abort on panic - -[profile.gh-release] -inherits = "release" +lto = true # Enable link-time optimization debug = true - -# The profile that 'dist' will build with -[profile.dist] -inherits = "release" -lto = "thin" - -[workspace.lints.rustdoc] -broken_intra_doc_links = "warn" +opt-level = 3 # Optimize for speed +codegen-units = 1 # Reduce number of codegen units to increase optimizations +panic = 'abort' # Abort on panic [workspace.lints.rust] missing_docs = "warn" -# missing_crate_level_docs = "warn" - -unexpected_cfgs = { level = "allow", check-cfg = [ - 'cfg(wasm_bindgen_unstable_test_coverage)', - 'cfg(noop)', - 'cfg(used_linker)', -] } [workspace.lints.clippy] uninlined_format_args = "warn" # missing_errors_doc = "warn" # missing_panics_doc = "warn" -# missing_docs_in_private_items = "warn" missing_safety_doc = "warn" undocumented_unsafe_blocks = "warn" -[workspace.metadata.typos.default] -locale = "en-us" - -[workspace.metadata.typos.default.extend-words] -labelled = "labelled" -onces = "onces" -withs = "withs" - -[workspace.metadata.typos.files] -ignore-hidden = false -extend-exclude = ["/.git", "fixtures"] - [patch.crates-io] -# This patch is used to bundle a locally built frontend (HTML) of `typst-preview`. -# The shortcoming is that you cannot install tinymist from git source then, i.e. `cargo install --git ..`, with this patch. -# However, it is not suggested to install it in that way. The suggested ways are: -# - Installation: https://github.com/Myriad-Dreamin/tinymist?tab=readme-ov-file#installation -# - Installing pre-built artifacts from GitHub : https://github.com/Myriad-Dreamin/tinymist?tab=readme-ov-file#installing-regularnightly-prebuilds-from-github -# tinymist-assets = { path = "./crates/tinymist-assets/" } -# These patches use a different version of `typst`, which only exports some private functions and information for code analysis. -# -# A regular build MUST use `tag` or `rev` to specify the version of the patched crate to ensure stability. -typst = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.14.6-rc2" } -typst-macros = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.14.6-rc2" } -typst-library = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.14.6-rc2" } -typst-html = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.14.6-rc2" } -typst-timing = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.14.6-rc2" } -typst-svg = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.14.6-rc2" } -typst-render = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.14.6-rc2" } -typst-pdf = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.14.6-rc2" } -typst-syntax = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.14.6-rc2" } -typst-eval = { git = "https://github.com/Myriad-Dreamin/typst.git", tag = "tinymist/v0.14.6-rc2" } +typst = { git = "https://github.com/Myriad-Dreamin/typst.git", branch = "tinymist-v0.11.0" } +typst-ide = { git = "https://github.com/Myriad-Dreamin/typst.git", branch = "tinymist-v0.11.0" } +typst-pdf = { git = "https://github.com/Myriad-Dreamin/typst.git", branch = "tinymist-v0.11.0" } +typst-syntax = { git = "https://github.com/Myriad-Dreamin/typst.git", branch = "tinymist-v0.11.0" } -# typst-ansi-hl = { git = "https://github.com/ParaN3xus/typst-ansi-hl.git", branch = "nightly" } -# typstyle-core = { git = "https://github.com/ParaN3xus/typstyle/", rev = "34869bfa9db089c5196be5fac2a5e9d752904ca2" } - -# These patches use local `typst` for development. # typst = { path = "../typst/crates/typst" } -# typst-timing = { path = "../typst/crates/typst-timing" } -# typst-svg = { path = "../typst/crates/typst-svg" } +# typst-ide = { path = "../typst/crates/typst-ide" } # typst-pdf = { path = "../typst/crates/typst-pdf" } -# typst-render = { path = "../typst/crates/typst-render" } # typst-syntax = { path = "../typst/crates/typst-syntax" } -# These patches use local `typstyle-core` for development. -# typstyle-core = { path = "../typstyle/crates/typstyle-core" } +typst-ts-svg-exporter = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "2fc877de0a4bcd7a8f057933546a97348e9621c7", package = "typst-ts-svg-exporter" } +typst-ts-core = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "2fc877de0a4bcd7a8f057933546a97348e9621c7", package = "typst-ts-core" } +typst-ts-compiler = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "2fc877de0a4bcd7a8f057933546a97348e9621c7", package = "typst-ts-compiler" } -# These patches use a different version of `reflexo`. -# -# A regular build MUST use `tag` or `rev` to specify the version of the patched crate to ensure stability. -reflexo = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "c078ddf869d9438b36e1cacb65100e4514780dc1" } -reflexo-typst = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "c078ddf869d9438b36e1cacb65100e4514780dc1" } -reflexo-vec2svg = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "c078ddf869d9438b36e1cacb65100e4514780dc1" } +# typst-ts-svg-exporter = { path = "../typst.ts/exporter/svg" } +# typst-ts-core = { path = "../typst.ts/core" } +# typst-ts-compiler = { path = "../typst.ts/compiler" } -# These patches use local `reflexo` for development. -# reflexo = { path = "../typst.ts/crates/reflexo/" } -# reflexo-typst = { path = "../typst.ts/crates/reflexo-typst/" } -# reflexo-vec2svg = { path = "../typst.ts/crates/conversion/vec2svg/" } - -typst-shim = { path = "crates/typst-shim" } -tinymist-analysis = { path = "crates/tinymist-analysis" } -tinymist-std = { path = "crates/tinymist-std" } -tinymist-vfs = { path = "crates/tinymist-vfs" } -tinymist-world = { path = "crates/tinymist-world" } -tinymist-project = { path = "crates/tinymist-project" } -tinymist-task = { path = "crates/tinymist-task" } - -# If reflexo use the tinymist from git, you should use the following patch. -# [patch."https://github.com/ParaN3xus/tinymist.git"] -# typst-shim = { path = "crates/typst-shim" } -# tinymist-analysis = { path = "crates/tinymist-analysis" } -# tinymist-std = { path = "crates/tinymist-std" } -# tinymist-vfs = { path = "crates/tinymist-vfs" } -# tinymist-world = { path = "crates/tinymist-world" } -# tinymist-project = { path = "crates/tinymist-project" } -# tinymist-task = { path = "crates/tinymist-task" } +# https://github.com/rust-lang/cargo/issues/8690 +[patch."https://github.com/Enter-tainer/typst-preview"] +typst-preview = { path = "external/typst-preview" } diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 4010d144c..000000000 --- a/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -# ```shell -# docker build -t myriaddreamin/tinymist:latest . -# ``` -# -# ## References -# -# https://stackoverflow.com/questions/58473606/cache-rust-dependencies-with-docker-build -# https://stackoverflow.com/a/64528456 -# https://depot.dev/blog/rust-dockerfile-best-practices - -ARG RUST_VERSION=1.89.0 - -FROM rust:${RUST_VERSION}-bookworm AS base -RUN apt-get install -y git -RUN cargo install sccache --version ^0.7 -RUN cargo install cargo-chef --version ^0.1 -ENV RUSTC_WRAPPER=sccache SCCACHE_DIR=/sccache -# to download the toolchain -RUN --mount=type=cache,target=/usr/local/cargo/registry \ - --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ - rustup update - -FROM base as planner -WORKDIR app -# We only pay the installation cost once, -# it will be cached from the second build onwards -RUN cargo install cargo-chef -COPY . . -RUN --mount=type=cache,target=/usr/local/cargo/registry \ - --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ - cargo +${RUST_VERSION} chef prepare --recipe-path recipe.json - -FROM base as builder -WORKDIR app -RUN cargo install cargo-chef -COPY --from=planner /app/recipe.json recipe.json -RUN --mount=type=cache,target=/usr/local/cargo/registry \ - --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ - cargo +${RUST_VERSION} chef cook --release --recipe-path recipe.json -COPY . . -RUN --mount=type=cache,target=/usr/local/cargo/registry \ - --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ - cargo +${RUST_VERSION} build --bin tinymist --release - -FROM debian:12 -WORKDIR /app/ -COPY --from=builder /app/target/release/tinymist /usr/local/bin -ENTRYPOINT ["/usr/local/bin/tinymist"] diff --git a/LICENSE b/LICENSE index 6bd3ac56d..31931256b 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2023-2025 Myriad Dreamin, Nathan Varner + Copyright 2023 Myriad Dreamin, Nathan Varner Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MAINTAINERS.md b/MAINTAINERS.md deleted file mode 100644 index 9e118afc5..000000000 --- a/MAINTAINERS.md +++ /dev/null @@ -1,56 +0,0 @@ - - -# Tinymist Maintainers - - -Tinymist [ˈtaɪni mɪst] is an integrated language service for [Typst](https://typst.app/) [taɪpst]. - -This page is generated from [./MAINTAINERS.typ](./MAINTAINERS.typ) and renders information of [maintainers](#maintainers) and [features.](#features) - -## Maintainers - -- [**Myriad-Dreamin**](https://github.com/Myriad-Dreamin) - - Email: camiyoru@gmail.com - - Maintains: *[Editor Integration](#editor-integration)*, *[Language Service](#language-service)*, *[Document Previewing](#document-previewing)*, *[VS Code Client-Side Support](#vs-code-client-side-support)*, and *[Nightly Releases](#nightly-releases)* - -- [**Enter-tainer**](https://github.com/Enter-tainer) - - Email: mgt@oi-wiki.org - - Maintains: *[Editor Integration](#editor-integration)*, *[Language Service](#language-service)*, *[Document Previewing](#document-previewing)*, and *[VS Code Client-Side Support](#vs-code-client-side-support)* - -- [**ParaN3xus**](https://github.com/ParaN3xus) - - Email: paran3xus007@gmail.com - - Maintains: *[Nightly Releases](#nightly-releases)* - -- [**Max397**](https://github.com/max397574) - - Email: undefined - - Maintains: *[Editor Integration](#editor-integration)* - -- [**Ericoolen**](https://github.com/Eric-Song-Nop) - - Email: EricYFSong@gmail.com - - Maintains: *[Language Service](#language-service)* - -- [**Caleb Maclennan**](https://github.com/alerque) - - Email: caleb@alerque.com - - Maintains: *[Editor Integration](#editor-integration)* - -- [**SylvanFranklin**](https://github.com/SylvanFranklin) - - Email: sylvanfranklin@icloud.com - - Maintains: *[Editor Integration](#editor-integration)*, and *[Document Previewing](#document-previewing)* - -## Features - -### Editor Integration - Integrate tinymist server with popular editors like VS Code, Neovim, etc. -- Scope: [`crates/tinymist/`](./crates/tinymist/), [`editors/`](./editors/) -### Language Service - Perform code analysis and provide language support for Typst. -- Scope: [`crates/tinymist/`](./crates/tinymist/), [`crates/tinymist-analysis/`](./crates/tinymist-analysis/), [`crates/tinymist-query/`](./crates/tinymist-query/) -### Document Previewing - Provide instant preview of the document being edited. -- Scope: [`crates/tinymist/`](./crates/tinymist/), [`crates/typst-preview/`](./crates/typst-preview/), [`contrib/typst-preview/`](./contrib/typst-preview/), [`tools/typst-dom/`](./tools/typst-dom/), [`tools/typst-preview-frontend/`](./tools/typst-preview-frontend/) -### VS Code Client-Side Support - Enrich the VS Code features with the client-side extension. -- Scope: [`crates/tinymist/`](./crates/tinymist/), [`editors/vscode/`](./editors/vscode/), [`tools/editor-tools/`](./tools/editor-tools/) -### Nightly Releases - Build and Publish nightly releases of tinymist. The nightly releases are built upon the main branches of both tinymist and typst. -- Scope: [`crates/tinymist/`](./crates/tinymist/), [`crates/typst-shim/`](./crates/typst-shim/) \ No newline at end of file diff --git a/MAINTAINERS.typ b/MAINTAINERS.typ deleted file mode 100644 index 8cbb284fb..000000000 --- a/MAINTAINERS.typ +++ /dev/null @@ -1,99 +0,0 @@ - -#import "typ/templates/maintainer.typ": * -#show: main - -#let editor-integration = [Editor Integration] -#let language-service = [Language Service] -#let document-previewing = [Document Previewing] -#let vs-code-client-side-support = [VS Code Client-Side Support] -#let nightly-releases = [Nightly Releases] - -== Maintainers - -#maintainers[ - - Myriad-Dreamin - - #github("Myriad-Dreamin") - - #email("camiyoru@gmail.com") - - #maintains[ - - #editor-integration - - #language-service - - #document-previewing - - #vs-code-client-side-support - - #nightly-releases - ] - - Enter-tainer - - #github("Enter-tainer") - - #email("mgt@oi-wiki.org") - - #maintains[ - - #editor-integration - - #language-service - - #document-previewing - - #vs-code-client-side-support - ] - - ParaN3xus - - #github("ParaN3xus") - - #email("paran3xus007@gmail.com") - - #maintains[ - - #nightly-releases - ] - - Max397 - - #github("max397574") - - #maintains[ - - #editor-integration - ] - - Ericoolen - - #github("Eric-Song-Nop") - - #email("EricYFSong@gmail.com") - - #maintains[ - - #language-service - ] - - Caleb Maclennan - - #github("alerque") - - #email("caleb@alerque.com") - - #maintains[ - - #editor-integration - ] - - SylvanFranklin - - #github("SylvanFranklin") - - #email("sylvanfranklin@icloud.com") - - #maintains[ - - #editor-integration - - #document-previewing - ] -] - -== Features - -#features[ - - #editor-integration - - #scope("crates/tinymist/", "editors/") - - #description[ - Integrate tinymist server with popular editors like VS Code, Neovim, etc. - ] - - #language-service - - #scope("crates/tinymist/", "crates/tinymist-analysis/", "crates/tinymist-query/") - - #description[ - Perform code analysis and provide language support for Typst. - ] - - #document-previewing - - #scope( - "crates/tinymist/", - "crates/typst-preview/", - "contrib/typst-preview/", - "tools/typst-dom/", - "tools/typst-preview-frontend/", - ) - - #description[ - Provide instant preview of the document being edited. - ] - - #vs-code-client-side-support - - #scope("crates/tinymist/", "editors/vscode/", "tools/editor-tools/") - - #description[ - Enrich the VS Code features with the client-side extension. - ] - - #nightly-releases - - #scope("crates/tinymist/", "crates/typst-shim/") - - #description[ - Build and Publish nightly releases of tinymist. The nightly releases are built upon the main branches of both tinymist and typst. - ] -] diff --git a/README.md b/README.md index fc5ddc0f8..4002f7d7b 100644 --- a/README.md +++ b/README.md @@ -1,228 +1,53 @@ - # Tinymist -[GitHub license](https://github.com/Myriad-Dreamin/tinymist/blob/main/LICENSE)[Actions status](https://github.com/Myriad-Dreamin/tinymist/actions/workflows/ci.yml)[Documentation](https://myriad-dreamin.github.io/tinymist/)[Ask DeepWiki](https://deepwiki.com/Myriad-Dreamin/tinymist) - -Tinymist \[ˈtaɪni mɪst\] is an integrated language service for [Typst](https://typst.app/) \[taɪpst\]. You can also call it - -微 - -wēi - - - - - -霭 - -ǎi - - - - in Chinese. +Tinymist [ˈtaɪni mɪst] is an integrated language service for [Typst](https://typst.app/) [taɪpst]. You can also call it "微霭" [wēi ǎi] in Chinese. It contains: - -- an analyzing library for Typst, see [tinymist-query](/crates/tinymist-query/). -- a CLI for Typst, see [tinymist](/crates/tinymist/). - - which provides a language server for Typst, see [Language Features](https://myriad-dreamin.github.io/tinymist/feature/language.html). - - which provides a preview server for Typst, see [Preview Feature](https://myriad-dreamin.github.io/tinymist/feature/preview.html). -- a VSCode extension for Typst, see [Tinymist VSCode Extension](/editors/vscode/). +- an analyzing library for Typst, see [tinymist-query](./crates/tinymist-query/). +- a CLI for Typst, see [tinymist](./crates/tinymist/). + - which provides a language server for Typst. +- a VSCode extension for Typst, see [Tinymist VSCode Extension](./editors/vscode/). ## Features Language service (LSP) features: - [Semantic highlighting](https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide) - - The “semantic highlighting” is supplementary to [“syntax highlighting”](https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide). -- [Code actions](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#provide-code-actions) - - Also known as “quick fixes” or “refactorings”. -- [Formatting (Reformatting)](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#format-source-code-in-an-editor) - - Provide the user with support for formatting whole documents, using [typstfmt](https://github.com/astrale-sharp/typstfmt) or [typstyle](https://github.com/Enter-tainer/typstyle). -- [Document highlight](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#highlight-all-occurrences-of-a-symbol-in-a-document) - - Highlight all break points in a loop context. - - (Todo) Highlight all exit points in a function context. - - (Todo) Highlight all captures in a closure context. - - (Todo) Highlight all occurrences of a symbol in a document. -- [Document links](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentLink) - - Renders path or link references in the document, such as `image("path.png")` or `bibliography(style: "path.csl")`. + - Also known as "syntax highlighting". +- [Diagnostics](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#provide-diagnostics) + - Also known as "error checking" or "error reporting". - [Document symbols](https://code.visualstudio.com/docs/getstarted/userinterface#_outline-view) - - Also known as “document outline” or “table of contents” _in Typst_. + - Also known as "document outline" or "table of contents" **in Typst**. - [Folding ranges](https://burkeholland.gitbook.io/vs-code-can-do-that/exercise-3-navigation-and-refactoring/folding-sections) - You can collapse code/content blocks and headings. - [Goto definitions](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-definitions-of-a-symbol) - - Right-click on a symbol and select “Go to Definition”. + - Right-click on a symbol and select "Go to Definition". - Or ctrl+click on a symbol. - [References](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#find-all-references-to-a-symbol) - - Right-click on a symbol and select “Go to References” or “Find References”. + - Right-click on a symbol and select "Go to References" or "Find References". - Or ctrl+click on a symbol. - [Hover tips](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-hovers) - - Also known as “hovering tooltip”. - - Render docs according to [tidy](https://github.com/Mc-Zen/tidy) style. + - Also known as "hovering tooltip". - [Inlay hints](https://www.jetbrains.com/help/idea/inlay-hints.html) - Inlay hints are special markers that appear in the editor and provide you with additional information about your code, like the names of the parameters that a called method expects. -- [Color Provider](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-color-decorators) - - View all inlay colorful label for color literals in your document. - - Change the color literal’s value by a color picker or its code presentation. - [Code Lens](https://code.visualstudio.com/blogs/2017/02/12/code-lens-roundup) - Should give contextual buttons along with code. For example, a button for exporting your document to various formats at the start of the document. -- [Rename symbols and embedded paths](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#rename-symbols) +- [Rename symbols](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#rename-symbols) - [Help with function and method signatures](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#help-with-function-and-method-signatures) - [Workspace Symbols](https://code.visualstudio.com/api/language-extensions/programmatic-language-features#show-all-symbol-definitions-in-folder) -- [Code Action](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-code-actions) - - Increasing/Decreasing heading levels. - - Turn equation into “inline”, “block” or “multiple-line block” styles. -- [experimental/onEnter](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#on-enter) - - - - Enter - - inside triple-slash comments automatically inserts `///` - - - - Enter - - in the middle or after a trailing space in `//` inserts `//` - - - - Enter - - inside `//!` doc comments automatically inserts `//!` - - - - Enter - - inside equation markups automatically inserts indents. Extra features: -- Compiles to PDF on save (configurable to as-you-type, or other options). Check [Docs: Exporting Documents](https://myriad-dreamin.github.io/tinymist/feature/export.html). -- Also compiles to SVG, PNG, HTML, Markdown, Text, and other formats by commands, vscode tasks, or code lenses. -- Provides test, benchmark, coverage collecting on documents and modules. Check [Docs: Testing Features](https://myriad-dreamin.github.io/tinymist/feature/testing.html). -- Provides builtin linting. Check [Docs: Linting Features](https://myriad-dreamin.github.io/tinymist/feature/linting.html). -- Provides a status bar item to show the current document’s compilation status and words count. -- [Editor tools](/tools/editor-tools/): - - View a list of templates in template gallery. (`tinymist.showTemplateGallery`) - - Click a button in template gallery to initialize a new project with a template. (`tinymist.initTemplate` and `tinymist.initTemplateInPlace`) - - Trace execution in current document (`tinymist.profileCurrentFile`). - -## Versioning and Release Cycle - -Tinymist’s versions follow the [Semantic Versioning](https://semver.org/) scheme, in format of `MAJOR.MINOR.PATCH`. Besides, tinymist follows special rules for the version number: - -- If a version is suffixed with `-rcN` ( - - typst-frame - - ), e.g. `0.11.0-rc1` and `0.12.1-rc1`, it means this version is a release candidate. It is used to test publish script and E2E functionalities. These versions will not be published to the marketplace. -- If the `PATCH` number is odd, e.g. `0.11.1` and `0.12.3`, it means this version is a nightly release. The nightly release will use both [tinymist](https://github.com/Myriad-Dreamin/tinymist/tree/main) and [typst](https://github.com/typst/typst/tree/main) at **main branch**. They will be published as prerelease version to the marketplace. Note that in nightly releases, we change `#sys.version` to the next minor release to help develop documents with nightly features. For example, in tinymist nightly v0.12.1 or v0.12.3, the `#sys.version` is changed to `version(0, 13, 0)`. -- Otherwise, if the `PATCH` number is even, e.g. `0.11.0` and `0.12.2`, it means this version is a regular release. The regular release will always use the recent stable version of tinymist and typst. - -The release cycle is as follows: - -- If there is a typst version update, a new major or minor version will be released intermediately. This means tinymist will always align the minor version with typst. -- If there is at least a bug or feature added this week, a new patch version will be released. +- Compiles to PDF on save (configurable to as-you-type, or other options) +- [Editor tools](https://github.com/Myriad-Dreamin/tinymist/tree/main/tools/editor-tools): + - View a list of templates in template gallery. + - Click a button in template gallery to initialize a new project with a template. ## Installation Follow the instructions to enable tinymist in your favorite editor. - -- [VS Cod(e,ium)](https://myriad-dreamin.github.io/tinymist/frontend/vscode.html) -- [Neovim](https://myriad-dreamin.github.io/tinymist/frontend/neovim.html) -- [Emacs](https://myriad-dreamin.github.io/tinymist/frontend/emacs.html) -- [Sublime Text](https://myriad-dreamin.github.io/tinymist/frontend/sublime-text.html) -- [Helix](https://myriad-dreamin.github.io/tinymist/frontend/helix.html) -- [Zed](https://myriad-dreamin.github.io/tinymist/frontend/zed.html) - -## Installing Regular/Nightly Prebuilds from GitHub - -Note: if you are not knowing what is a regular/nightly release, please don’t follow this section. - -Besides published releases specific for each editors, you can also download the latest regular/nightly prebuilts from GitHub and install them manually. - -- Regular prebuilts can be found in [GitHub Releases](https://github.com/Myriad-Dreamin/tinymist/releases). -- Nightly prebuilts can be found in [GitHub Actions](https://github.com/Myriad-Dreamin/tinymist/actions). - - (Suggested) Use the [tinymist-nightly-installer](https://github.com/hongjr03/tinymist-nightly-installer) to install the nightly prebuilts automatically. - - Unix (Bash): - ```bash - curl -sSL https://github.com/hongjr03/tinymist-nightly-installer/releases/latest/download/run.sh | bash - ``` - - Windows (PowerShell): - ```bash - iwr https://github.com/hongjr03/tinymist-nightly-installer/releases/latest/download/run.ps1 -UseBasicParsing | iex - ``` - - The prebuilts for other revisions can also be found manually. For example, if you are seeking a nightly release for the featured [PR: build: bump version to 0.11.17-rc1](https://github.com/Myriad-Dreamin/tinymist/pull/468), you could click and go to the [action page](https://github.com/Myriad-Dreamin/tinymist/actions/runs/10120639466) run for the related commits and download the artifacts. - -To install extension file (the file with `.vsix` extension) manually, please - -Ctrl+Shift+X - - in the editor window and drop the downloaded vsix file into the opened extensions view. - -## Documentation - -See [Online Documentation](https://myriad-dreamin.github.io/tinymist/). - -## Packaging - -Stable Channel: - - - -Packaging status - - - -Nightly Channel: - - - -Packaging status - - - -## Roadmap - -### Short Terms - -To encourage contributions, we create many [Pull Requests](https://github.com/Myriad-Dreamin/tinymist/pulls) in draft to navigate short-term plans. They give you a hint of what or where to start in this large repository. - -### Long Terms - -We are planning to implement the following features in typst v0.14.0 or spare time in weekend: - -- Type checking: complete the type checker. -- Periscope renderer: It is disabled since vscode reject to render SVGs containing foreignObjects. -- Inlay hint: It is disabled _by default_ because of performance issues. -- Find references of dictionary fields and named function arguments. -- Improve symbol view’s appearance. -- Improve package view. - - Navigate to symbols by clicking on the symbol name in the view. - - Automatically locate the symbol item in the view when viewing local documentation. - - Remember the recently invoked package commands, e.g. “Open Docs of @preview/cetz:0.3.1”, “Open directory of @preview/touying:0.5.3”. -- Improve label view. - - Group labels. - - Search labels. - - Keep (persist) group preferences. -- Improve Typst Preview. - - Pin drop-down: Set the file to preview in the drop-down for clients that doesn’t support passing arguments to the preview command. - - Render in web worker (another thread) to reduce overhead on the electron’s main thread. -- Spell checking: There is already a branch but no suitable (default) spell checking library is found. - - [typos](https://github.com/crate-ci/typos) is great for typst. [harper](https://github.com/Automattic/harper) looks promise. - -If you are interested by any above features, please feel free to send Issues to discuss or PRs to implement to [GitHub.](https://github.com/Myriad-Dreamin/tinymist) - -## Contributing - -Please read the [CONTRIBUTING.md](CONTRIBUTING.md) file for contribution guidelines. - -## Sponsoring - -Tinymist thrives on community love and remains proudly independent. While we don’t accept direct project funding, we warmly welcome support for our maintainers’ personal efforts. Please go to [Maintainers Page](/MAINTAINERS.md) and [Contributors Page](https://github.com/Myriad-Dreamin/tinymist/graphs/contributors) and find their personal pages for more information. It is also welcomed to directly ask questions about sponsoring on the [GitHub Issues](https://github.com/Myriad-Dreamin/tinymist/issues/new). ++ [VSCode](./editors/vscode/README.md) ## Acknowledgements - Partially code is inherited from [typst-lsp](https://github.com/nvarner/typst-lsp) -- The [integrating](/editors/vscode#symbol-view) **offline** handwritten-stroke recognizer is powered by [Detypify](https://detypify.quarticcat.com/). -- The [integrating](/editors/vscode#preview-command) preview service is powered by [typst-preview](https://github.com/Enter-tainer/typst-preview). -- The [integrating](/editors/vscode#managing-local-packages) local package management functions are adopted from [vscode-typst-sync](https://github.com/OrangeX4/vscode-typst-sync). diff --git a/_typos.toml b/_typos.toml deleted file mode 100644 index 00a71a346..000000000 --- a/_typos.toml +++ /dev/null @@ -1,4 +0,0 @@ -files.extend-exclude = [ - "locales/**/*", - "editors/vscode/e2e-workspaces/ieee-paper/ieee-tex.typ", -] diff --git a/assets/.gitignore b/assets/.gitignore deleted file mode 100644 index 6dafdaff7..000000000 --- a/assets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -fonts \ No newline at end of file diff --git a/assets/images/introduction/frame_0.svg b/assets/images/introduction/frame_0.svg deleted file mode 100644 index 5800678be..000000000 --- a/assets/images/introduction/frame_0.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/images/introduction/frame_1.svg b/assets/images/introduction/frame_1.svg deleted file mode 100644 index 28d607a07..000000000 --- a/assets/images/introduction/frame_1.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/benches/font-load/Cargo.toml b/benches/font-load/Cargo.toml deleted file mode 100644 index 20eef5b0e..000000000 --- a/benches/font-load/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "tinymist-bench-font-load" -description = "Font loading bench for tinymist." -authors.workspace = true -version.workspace = true -license.workspace = true -edition.workspace = true -homepage.workspace = true -repository.workspace = true - -[dependencies] -divan.workspace = true -tinymist.workspace = true - -[[bench]] -name = "tinymist-bench-font-load" -path = "src/load.rs" -harness = false - -[features] -the-thesis = [] diff --git a/benches/font-load/src/load.rs b/benches/font-load/src/load.rs deleted file mode 100644 index dc3c7483f..000000000 --- a/benches/font-load/src/load.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::sync::Arc; - -use tinymist::{Config, project::LspUniverseBuilder}; - -fn main() { - // initialize global variables - - // Run registered benchmarks. - divan::main(); -} - -// Checks font loading performance of embedded fonts -#[divan::bench] -fn load_embedded() { - let _embedded_fonts = Arc::new(LspUniverseBuilder::only_embedded_fonts().unwrap()); -} - -// Checks font loading performance of system fonts -#[divan::bench] -fn load_system() { - let config = Config::default(); - - let _fonts = config.fonts(); -} - -/* -Without Parallelization -Timer precision: 17 ns -tinymist_bench_font_load fastest │ slowest │ median │ mean │ samples │ iters -├─ load_embedded 1.167 ms │ 1.697 ms │ 1.176 ms │ 1.188 ms │ 100 │ 100 -╰─ load_system 111.8 ms │ 123 ms │ 113.6 ms │ 114.3 ms │ 100 │ 100 - -With Parallelization -Timer precision: 17 ns -tinymist_bench_font_load fastest │ slowest │ median │ mean │ samples │ iters -├─ load_embedded 130.8 µs │ 1.164 ms │ 157 µs │ 170.3 µs │ 100 │ 100 -╰─ load_system 14.44 ms │ 18.22 ms │ 15.37 ms │ 15.54 ms │ 100 │ 100 - - */ diff --git a/biome.json b/biome.json deleted file mode 100644 index 5c23d798f..000000000 --- a/biome.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "$schema": "https://biomejs.dev/schemas/2.3.5/schema.json", - "vcs": { - "enabled": false, - "clientKind": "git", - "useIgnoreFile": false - }, - "files": { - "ignoreUnknown": false - }, - "formatter": { - "enabled": true, - "indentStyle": "space", - "indentWidth": 2, - "lineWidth": 100 - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - }, - "javascript": { - "formatter": { - "arrowParentheses": "always", - "bracketSpacing": true, - "quoteStyle": "double", - "semicolons": "always", - "trailingCommas": "all" - } - }, - "assist": { - "actions": { - "source": { - "organizeImports": "on" - } - } - } -} diff --git a/contrib/html/editors/vscode/.gitignore b/contrib/html/editors/vscode/.gitignore deleted file mode 100644 index b7792b8a2..000000000 --- a/contrib/html/editors/vscode/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -tinymist-*.vsix -*.log -test-dist -.vscode-test -coverage -out/ \ No newline at end of file diff --git a/contrib/html/editors/vscode/.vscodeignore b/contrib/html/editors/vscode/.vscodeignore deleted file mode 100644 index 71c3c42ae..000000000 --- a/contrib/html/editors/vscode/.vscodeignore +++ /dev/null @@ -1,12 +0,0 @@ -** -!out/tinymist-docs.pdf -!out/extension.js -!out/extension.web.js -!out/server.js -!package.json -!package-lock.json -!icons/** -!syntaxes/** -!README.md -!LICENSE -!CHANGELOG.md diff --git a/contrib/html/editors/vscode/CHANGELOG.md b/contrib/html/editors/vscode/CHANGELOG.md deleted file mode 100644 index 136c67879..000000000 --- a/contrib/html/editors/vscode/CHANGELOG.md +++ /dev/null @@ -1,11 +0,0 @@ -# Change Log - -All notable changes to the "tinymist-html-ext" extension will be documented in this file. - -Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. - -The changelog lines unspecified with authors are all written by the @Myriad-Dreamin. - -## v0.13.0 - [2025-02-22] - -Initial release of the extension. diff --git a/contrib/html/editors/vscode/LICENSE b/contrib/html/editors/vscode/LICENSE deleted file mode 100644 index 6bd3ac56d..000000000 --- a/contrib/html/editors/vscode/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - 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 2023-2025 Myriad Dreamin, Nathan Varner - - 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. diff --git a/contrib/html/editors/vscode/esbuild.system.mjs b/contrib/html/editors/vscode/esbuild.system.mjs deleted file mode 100644 index 853446cd1..000000000 --- a/contrib/html/editors/vscode/esbuild.system.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import { build } from "esbuild"; -import * as fs from "fs"; - -if (!fs.existsSync("./out/extension.web.js")) { - fs.mkdirSync("./out", { recursive: true }); - fs.writeFileSync("./out/extension.web.js", ""); -} - -build({ - entryPoints: ["./src/extension.mts", "./src/server.mts"], - bundle: true, - outdir: "./out", - external: ["vscode"], - format: "cjs", - platform: "node", -}).catch(() => process.exit(1)); diff --git a/contrib/html/editors/vscode/esbuild.web.mjs b/contrib/html/editors/vscode/esbuild.web.mjs deleted file mode 100644 index eb98eadff..000000000 --- a/contrib/html/editors/vscode/esbuild.web.mjs +++ /dev/null @@ -1,29 +0,0 @@ -import { build } from "esbuild"; -import { polyfillNode } from "esbuild-plugin-polyfill-node"; -import * as fs from "fs"; - -if (!fs.existsSync("./out/extension.js")) { - fs.mkdirSync("./out", { recursive: true }); - fs.writeFileSync("./out/extension.js", ""); -} - -build({ - entryPoints: ["./src/extension.web.ts"], - bundle: true, - outfile: "./out/extension.web.js", - external: ["vscode"], - format: "cjs", - target: ["es2020", "chrome61", "edge18", "firefox60"], - // Node.js global to browser globalThis - define: { - global: "globalThis", - }, - plugins: [ - polyfillNode({ - polyfills: { - crypto: "empty", - }, - // Options (optional) - }), - ], -}).catch(() => process.exit(1)); diff --git a/contrib/html/editors/vscode/icons/ti-white.png b/contrib/html/editors/vscode/icons/ti-white.png deleted file mode 100644 index 452f72d1b..000000000 Binary files a/contrib/html/editors/vscode/icons/ti-white.png and /dev/null differ diff --git a/contrib/html/editors/vscode/package.json b/contrib/html/editors/vscode/package.json deleted file mode 100644 index b54d08d06..000000000 --- a/contrib/html/editors/vscode/package.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "name": "tinymist-vscode-html", - "version": "0.14.6-rc1", - "description": "Extending Typst with HTML features", - "keywords": [ - "html", - "typst", - "language-server" - ], - "categories": [ - "Programming Languages" - ], - "repository": { - "type": "git", - "url": "https://github.com/Myriad-Dreamin/tinymist.git" - }, - "displayName": "Tinymist Typst HTML", - "author": "Myriad-Dreamin", - "contributors": [ - "Myriad-Dreamin" - ], - "publisher": "myriad-dreamin", - "license": "Apache-2.0", - "engines": { - "vscode": "^1.97.0" - }, - "activationEvents": [ - "onLanguage:typst" - ], - "main": "./out/extension.js", - "browser": "./out/extension.web.js", - "icon": "./icons/ti-white.png", - "contributes": { - "commands": [ - { - "command": "tinymist.showHtmlExtensionLog", - "title": "Show Log of the HTML extension", - "description": "Show log of the tinymist HTML extension", - "category": "Typst", - "icon": "$(list-flat)" - } - ] - }, - "scripts": { - "build-web-base": "node esbuild.web.mjs", - "build-system-base": "node esbuild.system.mjs", - "build-base": "yarn run build-web-base && yarn run build-system-base", - "compile-shared": "node scripts/check-version.mjs && node scripts/postinstall.cjs", - "compile:web": "yarn run build-web-base -- --minify && yarn run compile-shared", - "compile:system": "yarn run build-system-base -- --minify && yarn run compile-shared", - "package": "npx @vscode/vsce package --yarn", - "compile": "yarn run compile:system", - "watch": "yarn run build-system-base -- --sourcemap --watch", - "check": "tsc --noEmit", - "format-check": "prettier --check .", - "format": "prettier --write .", - "test": "rimraf test-dist/ && tsc -p tsconfig.test.json && node test-dist/test/runTests.js" - }, - "dependencies": { - "css": "^3.0.0", - "esbuild-plugin-polyfill-node": "^0.3.0", - "lodash.flow": "^3.5.0", - "vscode-languageclient": "^9.0.0", - "vscode-languageserver": "^9.0.0", - "xxhashjs": "^0.2.2" - }, - "devDependencies": { - "@types/chai": "^5.0.1", - "@types/css": "^0.0.38", - "@types/mocha": "^10.0.1", - "@types/node": "^22.13.4", - "@types/vscode": "^1.97.0", - "@vscode/test-electron": "^2.3.9", - "@vscode/vsce": "^2.22.0", - "chai": "^5.1.1", - "mocha": "^10.2.0", - "ovsx": "^0.8.3", - "vscode-html-languageservice": "^5.3.1" - } -} \ No newline at end of file diff --git a/contrib/html/editors/vscode/scripts/check-version.mjs b/contrib/html/editors/vscode/scripts/check-version.mjs deleted file mode 100644 index 54567942b..000000000 --- a/contrib/html/editors/vscode/scripts/check-version.mjs +++ /dev/null @@ -1,15 +0,0 @@ -import { readFileSync } from "fs"; - -function check() { - const cargoToml = readFileSync("../../../../Cargo.toml", "utf8"); - const cargoVersion = cargoToml.match(/version = "(.*?)"/)[1]; - const pkgVersion = JSON.parse(readFileSync("package.json", "utf8")).version; - - if (cargoVersion !== pkgVersion) { - throw new Error( - `Version mismatch: ${cargoVersion} (in Cargo.toml) !== ${pkgVersion} (in package.json)`, - ); - } -} - -check(); diff --git a/contrib/html/editors/vscode/scripts/postinstall.cjs b/contrib/html/editors/vscode/scripts/postinstall.cjs deleted file mode 100644 index e69de29bb..000000000 diff --git a/contrib/html/editors/vscode/src/css/LICENSE b/contrib/html/editors/vscode/src/css/LICENSE deleted file mode 100644 index 052227f5c..000000000 --- a/contrib/html/editors/vscode/src/css/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -MIT License - -Copyright (c) 2023 Anders Ellenshøj Andersen - -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. \ No newline at end of file diff --git a/contrib/html/editors/vscode/src/css/arrayUtils.ts b/contrib/html/editors/vscode/src/css/arrayUtils.ts deleted file mode 100644 index 96a488435..000000000 --- a/contrib/html/editors/vscode/src/css/arrayUtils.ts +++ /dev/null @@ -1,35 +0,0 @@ -let XXH = require("xxhashjs").h32; - -export function flatten(nestedArray: T[][]): T[] { - if (nestedArray.length === 0) { - throw new RangeError("Can't flatten an empty array."); - } else { - return nestedArray.reduce((a, b) => a.concat(b)); - } -} - -export function distinct(items: T[] | Thenable): Thenable { - return Promise.resolve(items).then((items) => Array.from(new Set(items))); -} - -export function distinctByXXHash(items: T[] | Thenable): Thenable { - const initialValue = { - distinctItems: [], - hashSet: new Set(), - }; - - const accumulatorPromise = Promise.resolve(items).then((items) => - items.reduce((acc, item) => { - const hash = XXH(item, 0x1337).toNumber(); - - if (!acc.hashSet.has(hash)) { - acc.distinctItems.push(item); - acc.hashSet.add(hash); - } - - return acc; - }, initialValue), - ); - - return accumulatorPromise.then((accumulator) => accumulator.distinctItems); -} diff --git a/contrib/html/editors/vscode/src/css/cssAggregator.ts b/contrib/html/editors/vscode/src/css/cssAggregator.ts deleted file mode 100644 index b9deb1ea5..000000000 --- a/contrib/html/editors/vscode/src/css/cssAggregator.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { workspace, window } from "vscode"; -// @ts-ignore -import flow from "lodash.flow"; -import uriFilesReader from "./uriFilesReader"; -import { distinct, distinctByXXHash } from "./arrayUtils"; -import { parseCssTexts, getCSSRules, getCSSSelectors, getCSSClasses } from "./cssUtils"; - -const styleSheetsReader = flow(uriFilesReader, distinctByXXHash, parseCssTexts); -const distinctCSSClassesExtractor = flow(getCSSRules, getCSSSelectors, getCSSClasses, distinct); - -export default function (): Thenable { - const startTime = process.hrtime(); - - return styleSheetsReader( - workspace.findFiles("**/*.css", ""), - workspace.getConfiguration("files").get("encoding", "utf8"), - ).then((parseResult: any) => { - return distinctCSSClassesExtractor(parseResult.styleSheets).then((distinctCssClasses: any) => { - const elapsedTime = process.hrtime(startTime); - - console.log(`Elapsed time: ${elapsedTime[0]} s ${Math.trunc(elapsedTime[1] / 1e6)} ms`); - console.log(`Files processed: ${parseResult.styleSheets.length}`); - console.log(`Skipped due to parse errors: ${parseResult.unparsable.length}`); - console.log(`CSS classes discovered: ${distinctCssClasses.length}`); - - window.setStatusBarMessage( - `HTML Class Suggestions processed ${parseResult.styleSheets.length} distinct css files and discovered ${distinctCssClasses.length} css classes.`, - 10000, - ); - - return distinctCssClasses; - }); - }); -} diff --git a/contrib/html/editors/vscode/src/css/cssCompletionItemProvider.ts b/contrib/html/editors/vscode/src/css/cssCompletionItemProvider.ts deleted file mode 100644 index c9e32bcdb..000000000 --- a/contrib/html/editors/vscode/src/css/cssCompletionItemProvider.ts +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; -import * as vscode from "vscode"; -import aggregator from "./cssAggregator"; - -export class CssCompletionItemProvider { - public completionItems?: PromiseLike; - - constructor() { - this.refreshCompletionItems(); - } - - // public provideCompletionItems( - // document: vscode.TextDocument, - // position: vscode.Position, - // token: vscode.CancellationToken, - // ): Thenable { - // if (canTriggerCompletion(document, position)) { - // return this.completionItems as PromiseLike; - // } else { - // return Promise.reject("Not inside html class attribute."); - // } - // } - - public refreshCompletionItems() { - this.completionItems = aggregator().then((cssClasses) => { - const completionItems = cssClasses.map((cssClass) => { - const completionItem = new vscode.CompletionItem(cssClass); - completionItem.detail = `Insert ${cssClass}`; - completionItem.insertText = cssClass; - completionItem.kind = vscode.CompletionItemKind.Value; - - // make sure our completion item group are first - completionItem.preselect = true; - return completionItem; - }); - return completionItems; - }); - } -} diff --git a/contrib/html/editors/vscode/src/css/cssUtils.ts b/contrib/html/editors/vscode/src/css/cssUtils.ts deleted file mode 100644 index f1daed45f..000000000 --- a/contrib/html/editors/vscode/src/css/cssUtils.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { parse, Stylesheet, Rule, Media } from "css"; -import { flatten } from "./arrayUtils"; - -export interface CSSTextsParseResult { - styleSheets: Stylesheet[]; - unparsable: string[]; -} - -export function parseCssTexts( - cssTexts: string[] | Thenable, -): Thenable { - const initialValue = { - styleSheets: [], - unparsable: [], - }; - - return Promise.resolve(cssTexts).then((cssTexts) => - cssTexts.reduce((acc, cssText) => { - try { - acc.styleSheets.push(parse(cssText)); - } catch (error) { - acc.unparsable.push(cssText); - } - return acc; - }, initialValue), - ); -} - -export function getCSSRules(styleSheets: Stylesheet[] | Thenable): Thenable { - return Promise.resolve(styleSheets).then((styleSheets) => - styleSheets.reduce((acc, styleSheet) => { - return acc.concat(findRootRules(styleSheet), findMediaRules(styleSheet)); - }, [] as Rule[]), - ); -} - -export function getCSSSelectors(rules: Rule[] | Thenable): Thenable { - return Promise.resolve(rules).then((rules) => { - if (rules.length > 0) { - return flatten(rules.map((rule) => rule.selectors!)).filter( - (value) => value && value.length > 0, - ); - } else { - return []; - } - }); -} - -export function getCSSClasses(selectors: string[] | Thenable): Thenable { - return Promise.resolve(selectors).then((selectors) => - selectors.reduce((acc, selector) => { - const className = findClassName(selector); - - if (className && className.length > 0) { - acc.push(sanitizeClassName(className)); - } - - return acc; - }, [] as string[]), - ); -} - -export function findRootRules(cssAST: Stylesheet): Rule[] { - // @ts-ignore - return cssAST.stylesheet!.rules.filter((node) => (node).type === "rule"); -} - -export function findMediaRules(cssAST: Stylesheet): Rule[] { - let mediaNodes = cssAST.stylesheet!.rules.filter((node) => { - // @ts-ignore - return (node).type === "media"; - }); - if (mediaNodes.length > 0) { - // @ts-ignore - return flatten(mediaNodes.map((node) => (node).rules!)); - } else { - return []; - } -} - -export function findClassName(selector: string): string { - let classNameStartIndex = selector.lastIndexOf("."); - if (classNameStartIndex >= 0) { - let classText = selector.substr(classNameStartIndex + 1); - // Search for one of ' ', '[', ':' or '>', that isn't escaped with a backslash - let classNameEndIndex = classText.search(/[^\\][\s\[:>]/); - if (classNameEndIndex >= 0) { - return classText.substr(0, classNameEndIndex + 1); - } else { - return classText; - } - } else { - return ""; - } -} - -export function sanitizeClassName(className: string): string { - return className.replace(/\\[!"#$%&'()*+,\-./:;<=>?@[\\\]^`{|}~]/g, (substr, ...args) => { - if (args.length === 2) { - return substr.slice(1); - } else { - return substr; - } - }); -} diff --git a/contrib/html/editors/vscode/src/css/test/runTest.ts b/contrib/html/editors/vscode/src/css/test/runTest.ts deleted file mode 100644 index 93a4441de..000000000 --- a/contrib/html/editors/vscode/src/css/test/runTest.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as path from 'path'; - -import { runTests } from '@vscode/test-electron'; - -async function main() { - try { - // The folder containing the Extension Manifest package.json - // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath = path.resolve(__dirname, '../../'); - - // The path to test runner - // Passed to --extensionTestsPath - const extensionTestsPath = path.resolve(__dirname, './suite/index'); - - // Download VS Code, unzip it and run the integration test - await runTests({ extensionDevelopmentPath, extensionTestsPath }); - } catch (err) { - console.error('Failed to run tests', err); - process.exit(1); - } -} - -main(); diff --git a/contrib/html/editors/vscode/src/css/test/suite/cssUtils.test.ts b/contrib/html/editors/vscode/src/css/test/suite/cssUtils.test.ts deleted file mode 100644 index b0b49f2e5..000000000 --- a/contrib/html/editors/vscode/src/css/test/suite/cssUtils.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { findClassName, sanitizeClassName } from '../../cssUtils'; - -import * as assert from 'assert'; - -suite('Test cssUtils', () => { - suite('#findClassName', () => { - test('finds \'container\' in \'.container\'', () => { - assert.equal(findClassName('.container'), 'container'); - }); - test('finds \'bg-warning\' in \'a.bg-warning:hover\'', () => { - assert.equal(findClassName('a.bg-warning:hover'), 'bg-warning'); - }); - test('finds \'u-1\\/2\' in \'.u-1\\/2\'', () => { - assert.equal(findClassName('.u-1\\/2'), 'u-1\\/2'); - }); - test('finds \'ratio-16\\:9\' in \'.ratio-16\\:9\'', () => { - assert.equal(findClassName('.ratio-16\\:9'), 'ratio-16\\:9'); - }); - test('finds \'margin\\@palm\' in \'.margin\\@palm\'', () => { - assert.equal(findClassName('.margin\\@palm'), 'margin\\@palm'); - }); - - }); - suite('#sanitizeClassName', () => { - test('sanitizes \'u-1\\/2\' to \'u-1/2\'', () =>{ - assert.equal(sanitizeClassName('u-1\\/2'), 'u-1/2'); - }); - test('sanitizes \'ratio-16\\:9\' to \'ratio-16:9\'', () =>{ - assert.equal(sanitizeClassName('ratio-16\\:9'), 'ratio-16:9'); - }); - test('sanitizes \'margin\\@palm\' to \'margin@palm\'', () =>{ - assert.equal(sanitizeClassName('margin\\@palm'), 'margin@palm'); - }); - test('sanitizes \'foo-1\\/2\\@bar\' to \'foo-1/2@bar\'', () =>{ - assert.equal(sanitizeClassName('foo-1\\/2\\@bar'), 'foo-1/2@bar'); - }); - }); -}); diff --git a/contrib/html/editors/vscode/src/css/test/suite/index.ts b/contrib/html/editors/vscode/src/css/test/suite/index.ts deleted file mode 100644 index 2cb7d7d8b..000000000 --- a/contrib/html/editors/vscode/src/css/test/suite/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as path from "path"; -import * as Mocha from "mocha"; -import * as glob from "glob"; - -export function run(): Promise { - // Create the mocha test - const mocha = new Mocha({ - ui: "tdd", - color: true, - }); - - const testsRoot = path.resolve(__dirname, ".."); - - return new Promise((c, e) => { - glob("**/**.test.js", { cwd: testsRoot }, (err, files) => { - if (err) { - return e(err); - } - - // Add files to the test suite - files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); - - try { - // Run the mocha test - mocha.run((failures) => { - if (failures > 0) { - e(new Error(`${failures} tests failed.`)); - } else { - c(); - } - }); - } catch (err) { - console.error(err); - e(err); - } - }); - }); -} diff --git a/contrib/html/editors/vscode/src/css/test/suite/uriFilesReader.test.ts b/contrib/html/editors/vscode/src/css/test/suite/uriFilesReader.test.ts deleted file mode 100644 index 84977df97..000000000 --- a/contrib/html/editors/vscode/src/css/test/suite/uriFilesReader.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import uriFilesReader from "../../uriFilesReader"; -import * as assert from "assert"; -import { Uri } from "vscode"; - -suite("Test uriFilesReader", () => { - test("Can't load http protocol", () => { - const httpsUri = Uri.parse("https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"); - return uriFilesReader([httpsUri], "utf8").then((data: any) => { - assert(false, "Expected promise to be rejected."); - },(err: any) => { - assert(err.code === "ENOENT"); - }); - }); -}); diff --git a/contrib/html/editors/vscode/src/css/uriFilesReader.ts b/contrib/html/editors/vscode/src/css/uriFilesReader.ts deleted file mode 100644 index eaa1b3dfb..000000000 --- a/contrib/html/editors/vscode/src/css/uriFilesReader.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Uri } from "vscode"; -import { readFile } from "fs"; - -export default (uris: Uri[]|Thenable, encoding: BufferEncoding): Thenable => { - return Promise.resolve(uris).then(uris => { - return Promise.all(uris.map(uri => new Promise((resolve, reject) => { - readFile(uri.fsPath, encoding, (err, data) => { - if (err) { - reject(err); - } else { - resolve(data.toString()); - } - }); - }))); - }); -}; diff --git a/contrib/html/editors/vscode/src/embeddedSupport.ts b/contrib/html/editors/vscode/src/embeddedSupport.ts deleted file mode 100644 index 85b1c0202..000000000 --- a/contrib/html/editors/vscode/src/embeddedSupport.ts +++ /dev/null @@ -1,224 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -interface EmbeddedRegion { - languageId: string | undefined; - start: number; - end: number; - attributeValue?: boolean; -} - -enum TokenKind { - Unknown, - Colon, - String, - Identifier, -} - -class BackScanner { - currentToken: TokenKind = TokenKind.Unknown; - tokenContent: string = ""; - - constructor( - private documentText: string, - private offset: number, - ) { - this.scanBack(); - } - - getCurrentToken() { - return this.currentToken; - } - - scanBack() { - let i = this.offset; - this.currentToken = TokenKind.Unknown; - while (i >= 0) { - const ch = this.documentText[i]; - i--; - // console.log("scanBack", ch, this.currentToken, this.tokenContent); - if (this.currentToken === TokenKind.Unknown) { - if (ch === ":") { - this.currentToken = TokenKind.Colon; - this.tokenContent = ch; - break; - } else if (ch === '"') { - this.currentToken = TokenKind.String; - this.tokenContent = ch; - } else if (/[a-zA-Z0-9\-]/.test(ch)) { - this.currentToken = TokenKind.Identifier; - this.tokenContent = ch; - } else if (/\s/.test(ch)) { - // ignore - } else { - break; - } - } else if (this.currentToken === TokenKind.String) { - this.tokenContent = ch + this.tokenContent; - if (ch === '"') { - break; - } - } else if (this.currentToken === TokenKind.Identifier) { - if (/[a-zA-Z0-9\-]/.test(ch)) { - this.tokenContent = ch + this.tokenContent; - } else { - break; - } - } - } - this.offset = i; - } -} - -export function isInsideClassAttribute(documentText: string, offset: number) { - console.log("isInsideClassAttribute", offset); - - // string start - let start = offset - 1; - while (start >= 0) { - if (documentText[start] === '"') { - let shashCount = 0; - while (start > 0) { - if (documentText[start - 1] === "\\") { - shashCount++; - start--; - } else { - break; - } - } - - if (shashCount % 2 === 0) { - break; - } - - start--; - } else { - start--; - } - } - - if (start >= 0 && documentText[start] === '"') { - start -= 1; - - // find class attribute - const reverseScanner = new BackScanner(documentText, start); - if (reverseScanner.getCurrentToken() !== TokenKind.Colon) { - return false; - } - reverseScanner.scanBack(); - if (reverseScanner.getCurrentToken() === TokenKind.Identifier) { - console.log("found class attribute", reverseScanner.tokenContent); - return reverseScanner.tokenContent === "class"; - } - if (reverseScanner.getCurrentToken() === TokenKind.String) { - console.log("found class attribute", reverseScanner.tokenContent); - return reverseScanner.tokenContent === '"class"'; - } - } - - return false; -} - -export function parseRawBlockRegion( - documentText: string, - offset: number, -): EmbeddedRegion | undefined { - let start = offset - 1; - while (start >= 0) { - if (documentText[start] === "`") { - start -= 2; - if (start < 0 || documentText.slice(start, start + 3) !== "```") { - break; - } - - let languageOffset = start + 3; - let backtickStart = start; - while (backtickStart > 0 && documentText[backtickStart - 1] === "`") { - backtickStart -= 1; - } - - let numOfBackticks = languageOffset - backtickStart; - - let languageStart = languageOffset; - while (languageOffset < offset) { - if (/\s/.test(documentText[languageOffset])) { - break; - } - languageOffset++; - } - let languageId = documentText.slice(languageStart, languageOffset); - - console.log("numOfBackticks", numOfBackticks, languageOffset, languageId); - - let rawOffset = languageOffset; - let rawEnd = languageOffset; - let accumulatedBacktick = 0; - - while (rawEnd < documentText.length) { - const isBacktick = documentText[rawEnd] === "`"; - rawEnd++; - if (isBacktick) { - accumulatedBacktick++; - } else { - if (accumulatedBacktick >= numOfBackticks) { - break; - } - - accumulatedBacktick = 0; - } - } - - if (accumulatedBacktick > rawEnd) { - return; - } - rawEnd -= accumulatedBacktick; - - const rawContent = documentText.slice(rawOffset, rawEnd); - - console.log("raw content", languageId, rawOffset, rawEnd, rawContent); - - // return [languageId, rawOffset, rawEnd]; - return { - languageId, - start: rawOffset, - end: rawEnd, - }; - } - start--; - } - - return; -} - -/** - * Extract embedded regions from a document - * - * @param documentText The content of the document - * @param regions The regions to embed - * @param langId The language id to extract - * @returns The content of the document with the regions embedded - */ -export function getVirtualContent( - documentText: string, - regions: EmbeddedRegion[], - langId: string, -): string { - // Keeps space. - let content = documentText - .split("\n") - .map((line) => { - return " ".repeat(line.length); - }) - .join("\n"); - - regions.forEach((r) => { - if (r.languageId === langId) { - content = - content.slice(0, r.start) + documentText.slice(r.start, r.end) + content.slice(r.end); - } - }); - - return content; -} diff --git a/contrib/html/editors/vscode/src/extension.mts b/contrib/html/editors/vscode/src/extension.mts deleted file mode 100644 index 103dff7ab..000000000 --- a/contrib/html/editors/vscode/src/extension.mts +++ /dev/null @@ -1,142 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import * as path from "path"; -import * as vscode from "vscode"; -import { commands, CompletionList, ExtensionContext, Uri } from "vscode"; -import { - type LanguageClientOptions, - type ServerOptions, - LanguageClient, - TransportKind, -} from "vscode-languageclient/node"; -import { getVirtualContent, isInsideClassAttribute, parseRawBlockRegion } from "./embeddedSupport"; -import { cssActivate } from "./features/css"; - -let client: LanguageClient; - -export function activate(context: ExtensionContext) { - const tinymistExtension = vscode.extensions.getExtension("myriad-dreamin.tinymist"); - if (!tinymistExtension) { - void vscode.window.showWarningMessage( - "Tinymist HTML:\n\nTinymist LSP feature is required. Please install Tinymist Typst Extension (myriad-dreamin.tinymist).", - ); - } - - const provider = cssActivate(context); - - // The server is implemented in node - const serverModule = context.asAbsolutePath(path.join("out", "server.js")); - - // If the extension is launched in debug mode then the debug server options are used - // Otherwise the run options are used - const serverOptions: ServerOptions = { - run: { module: serverModule, transport: TransportKind.ipc }, - debug: { - module: serverModule, - transport: TransportKind.ipc, - }, - }; - - const virtualDocumentContents = new Map(); - - const removeSuffix = (uri: string) => uri.replace(/\.(html|css)$/, ""); - vscode.workspace.registerTextDocumentContentProvider("embedded-content", { - provideTextDocumentContent: (uri) => { - const originalUri = removeSuffix(uri.path.slice(1)); - const decodedUri = decodeURIComponent(originalUri); - console.log("provideTextDocumentContent gg", uri.path, originalUri, decodedUri); - return virtualDocumentContents.get(decodedUri); - }, - }); - - const clientOptions: LanguageClientOptions = { - documentSelector: [{ scheme: "file", language: "typst" }], - middleware: { - provideCompletionItem: async (document, position, context, token, next) => { - const res = await vscode.commands.executeCommand< - [{ mode: "math" | "markup" | "code" | "comment" | "string" | "raw" }] - >("tinymist.interactCodeContext", { - textDocument: { - uri: document.uri.toString(), - }, - query: [ - { - kind: "modeAt", - position: { - line: position.line, - character: position.character, - }, - }, - ], - }); - - const inString = res[0]?.mode === "string"; - const inRaw = res[0]?.mode === "raw"; - - // If completes the content of a `class` attribute, completes classes found in the css - // files. - if (inString && isInsideClassAttribute(document.getText(), document.offsetAt(position))) { - return provider.completionItems; - } - - if (!inRaw) { - return await next(document, position, context, token); - } - - // If not in ` -"#); - - for (name, sz, allocated, dropped, alive) in data { - html.push_str(""); - html.push_str(&format!(r#""#)); - html.push_str(&format!("")); - html.push_str(&format!("")); - html.push_str(&format!("")); - html.push_str(&format!("", human_size(sz))); - html.push_str(""); - } - html.push_str("
NameAliveAllocatedDroppedSize
{name}{alive}{allocated}{dropped}{}
"); - html.push_str(""); - - html - } -} - -/// The data of the query statistic. -#[derive(Clone)] -pub struct QueryStatBucketData { - pub(crate) query: u64, - pub(crate) missing: u64, - pub(crate) total: Duration, - pub(crate) min: Duration, - pub(crate) max: Duration, -} - -impl Default for QueryStatBucketData { - fn default() -> Self { - Self { - query: 0, - missing: 0, - total: Duration::from_secs(0), - min: Duration::from_secs(u64::MAX), - max: Duration::from_secs(0), - } - } -} - -/// Statistics about some query -#[derive(Default, Clone)] -pub struct QueryStatBucket { - /// The data of the query statistic. - pub data: Arc>, -} - -impl QueryStatBucket { - /// Increment the query statistic. - pub fn increment(&self, elapsed: Duration) { - let mut data = self.data.lock(); - data.query += 1; - data.total += elapsed; - data.min = data.min.min(elapsed); - data.max = data.max.max(elapsed); - } -} - -/// A guard for the query statistic. -pub struct QueryStatGuard { - /// The bucket of the query statistic for any file. - pub bucket_any: Option, - /// The bucket of the query statistic. - pub bucket: QueryStatBucket, - /// The start time of the query. - pub since: tinymist_std::time::Instant, -} - -impl Drop for QueryStatGuard { - fn drop(&mut self) { - let elapsed = self.since.elapsed(); - self.bucket.increment(elapsed); - if let Some(bucket) = self.bucket_any.as_ref() { - bucket.increment(elapsed); - } - } -} - -impl QueryStatGuard { - /// Increment the missing count. - pub fn miss(&self) { - let mut data = self.bucket.data.lock(); - data.missing += 1; - } -} - -/// Statistics about the analyzers -#[derive(Default)] -pub struct AnalysisStats { - /// The query statistics. - pub query_stats: Arc, FxDashMap<&'static str, QueryStatBucket>>>, -} - -impl AnalysisStats { - /// Gets a statistic guard for a query. - pub fn stat(&self, id: Option, name: &'static str) -> QueryStatGuard { - let stats = &self.query_stats; - let get = |v| stats.entry(v).or_default().entry(name).or_default().clone(); - QueryStatGuard { - bucket_any: if id.is_some() { Some(get(None)) } else { None }, - bucket: get(id), - since: tinymist_std::time::Instant::now(), - } - } - - /// Reports the statistics of the analysis. - pub fn report(&self) -> String { - let stats = &self.query_stats; - let mut data = Vec::new(); - for refs in stats.iter() { - let id = refs.key(); - let queries = refs.value(); - for refs2 in queries.iter() { - let query = refs2.key(); - let bucket = refs2.value().data.lock().clone(); - let name = match id { - Some(id) => format!("{id:?}:{query}"), - None => query.to_string(), - }; - let name = name.replace('\\', "/"); - data.push((name, bucket)); - } - } - - // sort by query duration - data.sort_by(|x, y| y.1.max.cmp(&x.1.max)); - - // format to html - - let mut html = String::new(); - html.push_str(r#"
- -"#); - - for (name, bucket) in data { - let _ = write!( - &mut html, - "", - bucket.query, bucket.missing, bucket.total, bucket.min, bucket.max - ); - } - html.push_str("
NameCountMissingTotalMinMax
{name}{}{}{:?}{:?}{:?}
"); - html.push_str("
"); - - html - } -} - -/// The global statistics about the analyzers. -pub static GLOBAL_STATS: LazyLock = LazyLock::new(AnalysisStats::default); - -fn human_size(size: usize) -> String { - let units = ["B", "KB", "MB", "GB", "TB"]; - let mut unit = 0; - let mut size = size as f64; - while size >= 768.0 && unit < units.len() { - size /= 1024.0; - unit += 1; - } - format!("{:.2} {}", size, units[unit]) -} diff --git a/crates/tinymist-analysis/src/syntax.rs b/crates/tinymist-analysis/src/syntax.rs deleted file mode 100644 index 66feca673..000000000 --- a/crates/tinymist-analysis/src/syntax.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Analyzing the syntax of a source file. -//! -//! This module must hide all **AST details** from the rest of the codebase. - -pub mod import; -pub use import::*; -pub mod comment; -pub use comment::*; -pub mod matcher; -pub use matcher::*; - -pub mod def; -pub use def::*; -pub(crate) mod repr; -use repr::*; diff --git a/crates/tinymist-analysis/src/syntax/comment.rs b/crates/tinymist-analysis/src/syntax/comment.rs deleted file mode 100644 index c2db8cba0..000000000 --- a/crates/tinymist-analysis/src/syntax/comment.rs +++ /dev/null @@ -1,301 +0,0 @@ -//! Convenient utilities to match comment in code. - -use itertools::Itertools; - -use crate::prelude::*; - -/// Extracts the module-level documentation from a source. -pub fn find_module_level_docs(src: &Source) -> Option { - crate::log_debug_ct!("finding docs at: {id:?}", id = src.id()); - - let root = LinkedNode::new(src.root()); - for n in root.children() { - if n.kind().is_trivia() { - continue; - } - - return extract_mod_docs_between(&root, 0..n.offset(), true); - } - - extract_mod_docs_between(&root, 0..src.text().len(), true) -} - -/// Extracts the module-level documentation from a source. -fn extract_mod_docs_between( - node: &LinkedNode, - rng: Range, - first_group: bool, -) -> Option { - let mut matcher = DocCommentMatcher { - strict: true, - ..Default::default() - }; - let nodes = node.children(); - 'scan_comments: for n in nodes { - let offset = n.offset(); - if offset < rng.start { - continue 'scan_comments; - } - if offset >= rng.end { - break 'scan_comments; - } - - crate::log_debug_ct!("found comment for docs: {:?}: {:?}", n.kind(), n.text()); - if matcher.process(n.get()) { - if first_group { - break 'scan_comments; - } - matcher.comments.clear(); - } - } - - matcher.collect() -} - -/// A signal raised by the comment group matcher. -pub enum CommentGroupSignal { - /// A hash marker is found. - Hash, - /// A space is found. - Space, - /// A line comment is found. - LineComment, - /// A block comment is found. - BlockComment, - /// The comment group should be broken. - BreakGroup, -} - -/// A matcher that groups comments. -#[derive(Default)] -pub struct CommentGroupMatcher { - newline_count: u32, -} - -impl CommentGroupMatcher { - /// Resets the matcher. This usually happens after a group is collected or - /// when some other child item is breaking the comment group manually. - pub fn reset(&mut self) { - self.newline_count = 0; - } - - /// Processes a child relative to some [`SyntaxNode`]. - /// - /// ## Example - /// - /// See [`DocCommentMatcher`] for a real-world example. - pub fn process(&mut self, n: &SyntaxNode) -> CommentGroupSignal { - match n.kind() { - SyntaxKind::Hash => { - self.newline_count = 0; - - CommentGroupSignal::Hash - } - SyntaxKind::Space => { - if n.text().contains('\n') { - self.newline_count += 1; - } - if self.newline_count > 1 { - return CommentGroupSignal::BreakGroup; - } - - CommentGroupSignal::Space - } - SyntaxKind::Parbreak => { - self.newline_count = 2; - CommentGroupSignal::BreakGroup - } - SyntaxKind::LineComment => { - self.newline_count = 0; - CommentGroupSignal::LineComment - } - SyntaxKind::BlockComment => { - self.newline_count = 0; - CommentGroupSignal::BlockComment - } - _ => { - self.newline_count = 0; - CommentGroupSignal::BreakGroup - } - } - } -} - -/// A raw comment. -enum RawComment { - /// A line comment. - Line(EcoString), - /// A block comment. - Block(EcoString), -} - -/// A matcher that collects documentation comments. -#[derive(Default)] -pub struct DocCommentMatcher { - /// The collected comments. - comments: Vec, - /// The matcher for grouping comments. - group_matcher: CommentGroupMatcher, - /// Whether to strictly match the comment format. - strict: bool, -} - -impl DocCommentMatcher { - /// Resets the matcher. This usually happens after a group is collected or - /// when some other child item is breaking the comment group manually. - pub fn reset(&mut self) { - self.comments.clear(); - self.group_matcher.reset(); - } - - /// Processes a child relative to some [`SyntaxNode`]. - pub fn process(&mut self, n: &SyntaxNode) -> bool { - match self.group_matcher.process(n) { - CommentGroupSignal::LineComment => { - let text = n.text(); - if !self.strict || text.starts_with("///") { - self.comments.push(RawComment::Line(text.clone())); - } - } - CommentGroupSignal::BlockComment => { - let text = n.text(); - if !self.strict { - self.comments.push(RawComment::Block(text.clone())); - } - } - CommentGroupSignal::BreakGroup => { - return true; - } - CommentGroupSignal::Hash | CommentGroupSignal::Space => {} - } - - false - } - - /// Collects the comments and returns the result. - pub fn collect(&mut self) -> Option { - let comments = &self.comments; - if comments.is_empty() { - return None; - } - - let comments = comments.iter().map(|comment| match comment { - RawComment::Line(line) => { - // strip all slash prefix - line.trim_start_matches('/') - } - RawComment::Block(block) => { - fn remove_comment(text: &str) -> Option<&str> { - let mut text = text.strip_prefix("/*")?.strip_suffix("*/")?.trim(); - // trip start star - if text.starts_with('*') { - text = text.strip_prefix('*')?.trim(); - } - Some(text) - } - - remove_comment(block).unwrap_or(block.as_str()) - } - }); - let comments = comments.collect::>(); - - let dedent = comments - .iter() - .flat_map(|line| { - let mut chars = line.chars(); - let cnt = chars - .by_ref() - .peeking_take_while(|c| c.is_whitespace()) - .count(); - chars.next().map(|_| cnt) - }) - .min() - .unwrap_or(0); - - let size_hint = comments.iter().map(|comment| comment.len()).sum::(); - let mut comments = comments - .iter() - .map(|comment| comment.chars().skip(dedent).collect::()); - - let res = comments.try_fold(String::with_capacity(size_hint), |mut acc, comment| { - if !acc.is_empty() { - acc.push('\n'); - } - - acc.push_str(&comment); - Some(acc) - }); - - self.comments.clear(); - res - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn test(it: &str) -> String { - find_module_level_docs(&Source::detached(it)).unwrap() - } - - #[test] - fn simple() { - assert_eq!( - test( - r#"/// foo -/// bar -#let main() = printf("hello World")"# - ), - "foo\nbar" - ); - } - - #[test] - fn dedent() { - assert_eq!( - test( - r#"/// a -/// b -/// c -#let main() = printf("hello World")"# - ), - "a\nb\nc" - ); - assert_eq!( - test( - r#"///a -/// b -/// c -#let main() = printf("hello World")"# - ), - "a\n b\n c" - ); - } - - #[test] - fn issue_1687_postive() { - assert_eq!( - test( - r#"/// Description. -/// -/// Note. -#let main() = printf("hello World")"# - ), - "Description.\n\nNote." - ); - } - - #[test] - fn issue_1687_negative() { - assert_eq!( - test( - r#"/// Description. -/// -/// Note. -#let main() = printf("hello World")"# - ), - "Description.\n\nNote." - ); - } -} diff --git a/crates/tinymist-analysis/src/syntax/def.rs b/crates/tinymist-analysis/src/syntax/def.rs deleted file mode 100644 index 0ad8cc0bb..000000000 --- a/crates/tinymist-analysis/src/syntax/def.rs +++ /dev/null @@ -1,1430 +0,0 @@ -//! Definitions of syntax structures. - -use core::fmt; -use std::{ - collections::BTreeMap, - ops::{Deref, Range}, - sync::Arc, -}; - -use rustc_hash::FxHashMap; -use serde::{Deserialize, Serialize}; -use tinymist_derive::DeclEnum; -use tinymist_std::DefId; -use tinymist_world::package::PackageSpec; -use typst::{ - foundations::{Element, Func, Module, Type, Value}, - syntax::{Span, SyntaxNode}, - utils::LazyHash, -}; - -use crate::{ - adt::interner::impl_internable, - docs::DocString, - prelude::*, - ty::{InsTy, Interned, SelectTy, Ty, TypeVar}, -}; - -use super::{ExprDescriber, ExprPrinter}; - -/// Information about expressions in a source file. -/// -/// This structure wraps expression analysis data and provides access to -/// expression resolution, documentation, and scoping information. -#[derive(Debug, Clone, Hash)] -pub struct ExprInfo(Arc>); - -impl ExprInfo { - /// Creates a new [`ExprInfo`] instance from expression information - /// representation. - /// - /// Wraps the provided representation in an Arc and LazyHash for efficient - /// sharing and hashing. - pub fn new(repr: ExprInfoRepr) -> Self { - Self(Arc::new(LazyHash::new(repr))) - } -} - -impl Deref for ExprInfo { - type Target = Arc>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -/// Representation of [`ExprInfo`] for a specific file. -/// -/// Contains all the analyzed information including resolution maps, -/// documentation strings, imports, and exports. -#[derive(Debug)] -pub struct ExprInfoRepr { - /// The file ID this expression information belongs to. - pub fid: TypstFileId, - /// Revision number for tracking changes to the file. - pub revision: usize, - /// The source code content. - pub source: Source, - /// The root expression of the file. - pub root: Expr, - /// Documentation string for the module. - pub module_docstring: Arc, - /// The lexical scope of exported symbols from this file. - pub exports: Arc>, - /// Map from file IDs to imported lexical scopes. - pub imports: FxHashMap>>, - /// Map from spans to expressions for scope analysis. - pub exprs: FxHashMap, - /// Map from spans to resolved reference expressions. - pub resolves: FxHashMap>, - /// Map from declarations to their documentation strings. - pub docstrings: FxHashMap>, - /// Layout information for module import items in this file. - pub module_items: FxHashMap, ModuleItemLayout>, -} - -impl std::hash::Hash for ExprInfoRepr { - fn hash(&self, state: &mut H) { - // already contained in the source. - // self.fid.hash(state); - self.revision.hash(state); - self.source.hash(state); - self.root.hash(state); - self.exports.hash(state); - let mut resolves = self.resolves.iter().collect::>(); - resolves.sort_by_key(|(fid, _)| fid.into_raw()); - resolves.hash(state); - let mut imports = self.imports.iter().collect::>(); - imports.sort_by_key(|(fid, _)| *fid); - imports.hash(state); - let mut module_items = self.module_items.iter().collect::>(); - module_items.sort_by_key(|(decl, _)| decl.span().into_raw()); - module_items.hash(state); - } -} - -impl ExprInfoRepr { - /// Gets the definition expression for a given declaration. - pub fn get_def(&self, decl: &Interned) -> Option { - if decl.is_def() { - return Some(Expr::Decl(decl.clone())); - } - let resolved = self.resolves.get(&decl.span())?; - Some(Expr::Ref(resolved.clone())) - } - - /// Gets all references to a given declaration. - pub fn get_refs( - &self, - decl: Interned, - ) -> impl Iterator)> { - let of = Some(Expr::Decl(decl.clone())); - self.resolves - .iter() - .filter(move |(_, r)| match (decl.as_ref(), r.decl.as_ref()) { - (Decl::Label(..), Decl::Label(..)) => r.decl == decl, - (Decl::Label(..), Decl::ContentRef(..)) => r.decl.name() == decl.name(), - (Decl::Label(..), _) => false, - _ => r.decl == decl || r.root == of, - }) - } - - /// Checks if a declaration is exported from this module. - pub fn is_exported(&self, decl: &Interned) -> bool { - let of = Expr::Decl(decl.clone()); - self.exports - .get(decl.name()) - .is_some_and(|export| match export { - Expr::Ref(ref_expr) => ref_expr.root == Some(of), - exprt => *exprt == of, - }) - } - - /// Shows the expression information. - #[allow(dead_code)] - fn show(&self) { - use std::io::Write; - let vpath = self - .fid - .vpath() - .resolve(Path::new("target/exprs/")) - .unwrap(); - let root = vpath.with_extension("root.expr"); - std::fs::create_dir_all(root.parent().unwrap()).unwrap(); - std::fs::write(root, format!("{}", self.root)).unwrap(); - let scopes = vpath.with_extension("scopes.expr"); - std::fs::create_dir_all(scopes.parent().unwrap()).unwrap(); - { - let mut scopes = std::fs::File::create(scopes).unwrap(); - for (span, expr) in self.exprs.iter() { - writeln!(scopes, "{span:?} -> {expr}").unwrap(); - } - } - let imports = vpath.with_extension("imports.expr"); - std::fs::create_dir_all(imports.parent().unwrap()).unwrap(); - std::fs::write(imports, format!("{:#?}", self.imports)).unwrap(); - let exports = vpath.with_extension("exports.expr"); - std::fs::create_dir_all(exports.parent().unwrap()).unwrap(); - std::fs::write(exports, format!("{:#?}", self.exports)).unwrap(); - } -} - -/// Describes how an import item is laid out in the source text. -#[derive(Debug, Clone, Hash)] -pub struct ModuleItemLayout { - /// The module declaration that owns this item. - pub parent: Interned, - /// The byte range covering the whole `foo as bar` clause. - pub item_range: Range, - /// The byte range covering the bound identifier (`bar` in `foo as bar`). - pub binding_range: Range, -} - -/// Represents different kinds of expressions in the language. -/// -/// This enum covers all possible expression types that can appear in Typst -/// source code, from basic literals to complex control flow constructs. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Expr { - /// A sequence of expressions: `{ x; y; z }` - Block(Interned>), - /// An array literal: `(1, 2, 3)` - Array(Interned), - /// A dict literal: `(a: 1, b: 2)` - Dict(Interned), - /// An args literal: `(1, 2, 3)` - Args(Interned), - /// A pattern: `(x, y, ..z)` - Pattern(Interned), - /// An element literal: `[*Hi* there!]` - Element(Interned), - /// An unary operation: `-x` - Unary(Interned), - /// A binary operation: `x + y` - Binary(Interned), - /// A function call: `f(x, y)` - Apply(Interned), - /// A function: `(x, y) => x + y` - Func(Interned), - /// A let: `let x = 1` - Let(Interned), - /// A show: `show heading: it => emph(it.body)` - Show(Interned), - /// A set: `set text(...)` - Set(Interned), - /// A reference: `#x` - Ref(Interned), - /// A content reference: `@x` - ContentRef(Interned), - /// A select: `x.y` - Select(Interned), - /// An import expression: `import "path.typ": x` - Import(Interned), - /// An include expression: `include "path.typ"` - Include(Interned), - /// A contextual expression: `context text.lang` - Contextual(Interned), - /// A conditional expression: `if x { y } else { z }` - Conditional(Interned), - /// A while loop: `while x { y }` - WhileLoop(Interned), - /// A for loop: `for x in y { z }` - ForLoop(Interned), - /// A type: `str` - Type(Ty), - /// A declaration: `x` - Decl(DeclExpr), - /// A star import: `*` - Star, -} - -impl Expr { - /// Returns a string representation of the expression. - pub fn repr(&self) -> EcoString { - let mut s = EcoString::new(); - let _ = ExprDescriber::new(&mut s).write_expr(self); - s - } - - /// Returns the span location of the expression. - pub fn span(&self) -> Span { - match self { - Expr::Decl(decl) => decl.span(), - Expr::Select(select) => select.span, - Expr::Apply(apply) => apply.span, - _ => Span::detached(), - } - } - - /// Returns the file ID associated with this expression, if any. - pub fn file_id(&self) -> Option { - match self { - Expr::Decl(decl) => decl.file_id(), - _ => self.span().id(), - } - } - - /// Returns whether the expression is definitely defined. - pub fn is_defined(&self) -> bool { - match self { - Expr::Ref(refs) => refs.root.is_some() || refs.term.is_some(), - Expr::Decl(decl) => decl.is_def(), - // There are unsure cases, like `x.y`, which may be defined or not. - _ => false, - } - } -} - -impl fmt::Display for Expr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - ExprPrinter::new(f).write_expr(self) - } -} - -/// Type alias for lexical scopes. -/// -/// Represents a lexical scope as a persistent map from names to expressions. -pub type LexicalScope = rpds::RedBlackTreeMapSync, Expr>; - -/// Different types of scopes for expression evaluation. -/// -/// Represents the various kinds of scopes that can contain variable bindings, -/// including lexical scopes, modules, functions, and types. -#[derive(Debug, Clone)] -pub enum ExprScope { - /// A lexical scope extracted from a source file. - Lexical(LexicalScope), - /// A module instance which is either built-in or evaluated during analysis. - Module(Module), - /// A scope bound to a function. - Func(Func), - /// A scope bound to a type. - Type(Type), -} - -impl ExprScope { - /// Creates an empty lexical scope. - pub fn empty() -> Self { - ExprScope::Lexical(LexicalScope::default()) - } - - /// Checks if the scope contains no bindings. - pub fn is_empty(&self) -> bool { - match self { - ExprScope::Lexical(scope) => scope.is_empty(), - ExprScope::Module(module) => is_empty_scope(module.scope()), - ExprScope::Func(func) => func.scope().is_none_or(is_empty_scope), - ExprScope::Type(ty) => is_empty_scope(ty.scope()), - } - } - - /// Looks up a name in the scope and returns both expression and type - /// information. - pub fn get(&self, name: &Interned) -> (Option, Option) { - let (of, val) = match self { - ExprScope::Lexical(scope) => { - crate::log_debug_ct!("evaluating: {name:?} in {scope:?}"); - (scope.get(name).cloned(), None) - } - ExprScope::Module(module) => { - let v = module.scope().get(name); - // let decl = - // v.and_then(|_| Some(Decl::external(module.file_id()?, - // name.clone()).into())); - (None, v) - } - ExprScope::Func(func) => (None, func.scope().unwrap().get(name)), - ExprScope::Type(ty) => (None, ty.scope().get(name)), - }; - - // ref_expr.of = of.clone(); - // ref_expr.val = val.map(|v| Ty::Value(InsTy::new(v.clone()))); - // return ref_expr; - ( - of, - val.cloned() - .map(|val| Ty::Value(InsTy::new(val.read().to_owned()))), - ) - } - - /// Merges all bindings from this scope into the provided export map. - pub fn merge_into(&self, exports: &mut LexicalScope) { - match self { - ExprScope::Lexical(scope) => { - for (name, expr) in scope.iter() { - exports.insert_mut(name.clone(), expr.clone()); - } - } - ExprScope::Module(module) => { - crate::log_debug_ct!("imported: {module:?}"); - let v = Interned::new(Ty::Value(InsTy::new(Value::Module(module.clone())))); - for (name, _) in module.scope().iter() { - let name: Interned = name.into(); - exports.insert_mut(name.clone(), select_of(v.clone(), name)); - } - } - ExprScope::Func(func) => { - if let Some(scope) = func.scope() { - let v = Interned::new(Ty::Value(InsTy::new(Value::Func(func.clone())))); - for (name, _) in scope.iter() { - let name: Interned = name.into(); - exports.insert_mut(name.clone(), select_of(v.clone(), name)); - } - } - } - ExprScope::Type(ty) => { - let v = Interned::new(Ty::Value(InsTy::new(Value::Type(*ty)))); - for (name, _) in ty.scope().iter() { - let name: Interned = name.into(); - exports.insert_mut(name.clone(), select_of(v.clone(), name)); - } - } - } - } -} - -fn select_of(source: Interned, name: Interned) -> Expr { - Expr::Type(Ty::Select(SelectTy::new(source, name))) -} - -/// Kind of a definition. -#[derive(Debug, Default, Clone, Copy, Hash, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum DefKind { - /// A definition for some constant: `let x = 1` - #[default] - Constant, - /// A definition for some function: `(x, y) => x + y` - Function, - /// A definition for some variable: `let x = (x, y) => x + y` - Variable, - /// A definition for some module. - Module, - /// A definition for some struct (type). - Struct, - /// A definition for some reference: `