diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 635590b53..277496c14 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -24,11 +24,19 @@ jobs:
build:
strategy:
matrix:
- os: [ ubuntu-20.04, windows-latest, macos-latest ]
+ os: [ ubuntu-latest, macos-latest, windows-latest ]
+ include:
+ - os: ubuntu-latest
+ image: "debian:10"
fail-fast: false
runs-on: ${{ matrix.os }}
+ container: ${{ matrix.image }}
steps:
+ - name: Install build dependencies - Linux
+ if: ${{ runner.os == 'Linux' }}
+ run: apt-get update && apt-get install -y git python3 python3-pip make gcc g++ libx11-dev libxkbfile-dev pkg-config libsecret-1-dev rpm xvfb ffmpeg zstd
+
- name: Checkout the latest code
uses: actions/checkout@v3
@@ -38,6 +46,10 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Setup Python
+ # actions/setup-python's copy of Python is compiled for too new glibc,
+ # which won't work in a Debian 10 Docker image.
+ # Get Python from apt repos instead on Linux.
+ if: ${{ runner.os != 'Linux' }}
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
@@ -48,11 +60,23 @@ jobs:
# out of the box. 'setuptools' package provides 'distutils'.
run: python3 -m pip install setuptools
+ - name: Install Yarn - Linux
+ if: ${{ runner.os == 'Linux' }}
+ run: npm install -g yarn
+
- name: Setup Git Submodule
+ if: ${{ runner.os != 'Linux' }}
run: |
git submodule init
git submodule update
+ - name: Setup Git Submodule - Linux
+ if: ${{ runner.os == 'Linux' }}
+ run: |
+ git config --global --add safe.directory /__w/pulsar/pulsar
+ git submodule init
+ git submodule update
+
- name: Check Pulsar Version
if: ${{ runner.os != 'Windows' }}
run: sed -i -e "s/[0-9]*-dev/`date -u +%Y%m%d%H`/g" package.json
@@ -86,6 +110,15 @@ jobs:
yarn build
yarn run build:apm
+ - name: Cache Pulsar dependencies - Linux
+ if: ${{ runner.os == 'Linux' }}
+ uses: actions/cache/save@v3
+ with:
+ path: |
+ node_modules
+ packages
+ key: Linux-dependencies-${{ github.sha }}-${{ github.workflow }}
+
# macOS Signing Stuff
- name: Build Pulsar Binaries (macOS) (Signed)
if: ${{ runner.os == 'macOS' && github.event_name == 'push' }}
@@ -135,21 +168,19 @@ jobs:
if: ${{ runner.os == 'Windows' }}
run: node ./script/rename.js "Windows"
+ - name: Cache Pulsar Binaries - Linux
+ if: ${{ runner.os == 'Linux' }}
+ uses: actions/cache/save@v3
+ with:
+ path: ./binaries
+ key: pulsar-Linux-Binaries-${{ github.sha }}-${{ github.workflow }}
+
- name: Upload Binary Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.os }} Binaries
path: ./binaries/*
- - name: Test Binary - Linux
- if: ${{ (runner.os == 'Linux') && env.RUN_LINUX_VT }}
- run: |
- rm -R node_modules/electron; yarn install --check-files
- ./binaries/*AppImage --appimage-extract
- export BINARY_NAME='squashfs-root/pulsar'
- mkdir -p ./tests/videos
- Xvfb -screen 0 1024x768x24+32 :99 & nohup ffmpeg -video_size 1024x768 -f x11grab -i :99.0 ./tests/videos/out.mpg & DISPLAY=:99 PLAYWRIGHT_JUNIT_OUTPUT_NAME=report.xml npx playwright test --reporter=junit,list
-
- name: Test Binary - Windows
if: runner.os == 'Windows' && env.RUN_WINDOWS_VT == true
# TODO: Convert script to PowerShell
@@ -168,7 +199,7 @@ jobs:
PLAYWRIGHT_JUNIT_OUTPUT_NAME=report.xml arch -x86_64 npx playwright test --reporter=junit,list
- name: Add binaries to Rolling Release Repo
- if: ${{ github.event_name == 'push' }}
+ if: ${{ github.event_name == 'push' && runner.os != 'Linux' }}
# We only want to upload rolling binaries if they are a commit to master
# Otherwise we want to not upload if it's a PR or manually triggered build
run: |
@@ -178,7 +209,67 @@ jobs:
- name: Upload Video Artifacts
# Run whether this job passed or failed, unless explicitly cancelled.
- if: '!cancelled()'
+ if: ${{ !cancelled() && runner.os != 'Linux' }}
+ uses: actions/upload-artifact@v3
+ with:
+ name: ${{ matrix.os }} Videos
+ path: ./tests/videos/**
+
+
+ test-and-upload-Linux:
+ # I couldn't figure out how to get these visual tests to actually run in the
+ # Debian Docker environment. If anyone can make it work, feel free to
+ # re-combine visual testing on Linux back into the main build job above!
+ # - DeeDeeG
+ runs-on: ubuntu-latest
+ needs: build
+
+ steps:
+ - name: Checkout the latest code
+ uses: actions/checkout@v3
+
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+
+ - name: Restore Cached Pulsar Binaries - Linux
+ if: ${{ runner.os == 'Linux' }}
+ uses: actions/cache/restore@v3
+ with:
+ path: ./binaries
+ key: pulsar-Linux-Binaries-${{ github.sha }}-${{ github.workflow }}
+
+ - name: Restore Cached Pulsar dependencies - Linux
+ if: ${{ runner.os == 'Linux' }}
+ uses: actions/cache/restore@v3
+ with:
+ path: |
+ node_modules
+ packages
+ key: Linux-dependencies-${{ github.sha }}-${{ github.workflow }}
+
+ - name: Test Binary - Linux
+ if: ${{ (runner.os == 'Linux') && env.RUN_LINUX_VT }}
+ run: |
+ rm -R node_modules/electron; yarn install --check-files
+ ./binaries/*AppImage --appimage-extract
+ export BINARY_NAME='squashfs-root/pulsar'
+ mkdir -p ./tests/videos
+ Xvfb -screen 0 1024x768x24+32 :99 & nohup ffmpeg -video_size 1024x768 -f x11grab -i :99.0 ./tests/videos/out.mpg & DISPLAY=:99 PLAYWRIGHT_JUNIT_OUTPUT_NAME=report.xml npx playwright test --reporter=junit,list
+
+ - name: Add binaries to Rolling Release Repo - Linux
+ if: ${{ github.event_name == 'push' && runner.os == 'Linux' }}
+ # We only want to upload rolling binaries if they are a commit to master
+ # Otherwise we want to not upload if it's a PR or manually triggered build
+ run: |
+ cd ./script/rolling-release-scripts
+ npm install
+ node ./rolling-release-binary-upload.js
+
+ - name: Upload Video Artifacts - Linux
+ # Run whether this job passed or failed, unless explicitly cancelled.
+ if: ${{ !cancelled() && runner.os == 'Linux' }}
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.os }} Videos
diff --git a/LICENSE.md b/LICENSE.md
index 50a586694..5c07eeda9 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2022-2023 Pulsar-Edit
+Copyright (c) 2022-2024 Pulsar-Edit
Original work copyright (c) 2011-2022 GitHub Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/README.md b/README.md
index 149f4f8b9..82f1a1258 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,9 @@
[![Badge Discussions]][Discussions]
[![Badge Discord]][Discord]
-[![Badge Reddit]][Reddit]
+[![Badge Reddit]][Reddit]
+[![Badge Mastodon]][Mastodon]
+[![Badge Lemmy]][Lemmy]
[![Badge Status]][Status]
[![Badge License]][License]
@@ -51,6 +53,8 @@
[Status]: https://cirrus-ci.com/github/pulsar-edit/pulsar/master
[Codacy]: https://app.codacy.com/gh/pulsar-edit/pulsar
[Reddit]: https://www.reddit.com/r/pulsaredit/
+[Mastodon]: https://fosstodon.org/@pulsaredit/
+[Lemmy]: https://lemmy.ml/c/pulsaredit/
[#]: #
@@ -72,14 +76,18 @@
[Badge OpenCollective]: https://opencollective.com/pulsar-edit/tiers/badge.svg
-[Badge Discussions]: https://img.shields.io/github/discussions/pulsar-edit/.github?style=for-the-badge&labelColor=78af9f&color=5a8377
+[Badge Discussions]: https://img.shields.io/github/discussions/pulsar-edit/.github?style=for-the-badge&logo=GitHub&labelColor=50555b&color=35393d
[Badge Upstream]: https://img.shields.io/badge/Upstream_Status-Sunset-966227.svg?style=for-the-badge&labelColor=c38033
[Badge Discord]: https://img.shields.io/badge/Discord-4b7494.svg?style=for-the-badge&labelColor=6399c4&logoColor=white&logo=Discord
[Badge License]: https://img.shields.io/badge/License-MIT-ac7f31.svg?style=for-the-badge&labelColor=e5ab42
[Badge Crowdin]: https://badges.crowdin.net/pulsar-edit/localized.svg
[Badge Codacy]: https://app.codacy.com/project/badge/Grade/24873ecb93dc4c1d865202ce5b24efc1
-[Badge Reddit]: https://img.shields.io/reddit/subreddit-subscribers/pulsaredit?style=for-the-badge&label=Reddit&logoColor=white&logo=Reddit&labelColor=e05d44&color=b14835
+
+
+[Badge Reddit]: https://img.shields.io/badge/%2Fr%2Fpulsaredit-e05d44?style=for-the-badge&logo=Reddit&logoColor=white&labelColor=e05d44&color=b14835
[Badge Status]: https://img.shields.io/cirrus/github/pulsar-edit/pulsar?style=for-the-badge&labelColor=c77b7f&label=Build%20Status&color=8d575a
+[Badge Mastodon]: https://img.shields.io/mastodon/follow/109416671848539153?domain=https%3A%2F%2Ffosstodon.org%2F&style=for-the-badge&logo=Mastodon&logoColor=white&label=Mastodon&labelColor=a0a0d8&color=7c7cc1
+[Badge Lemmy]: https://img.shields.io/lemmy/pulsaredit%40lemmy.ml?style=for-the-badge&logo=Lemmy&logoColor=white&label=Lemmy&labelColor=64ad82&color=1d9b52
diff --git a/spec/scope-resolver-spec.js b/spec/scope-resolver-spec.js
index 51bced5b7..0aee61c60 100644
--- a/spec/scope-resolver-spec.js
+++ b/spec/scope-resolver-spec.js
@@ -132,6 +132,38 @@ describe('ScopeResolver', () => {
}
});
+ it('provides the grammar with the text of leaf nodes only', async () => {
+ await grammar.setQueryForTest('highlightsQuery', `
+ (expression_statement) @not_leaf_node
+ (call_expression) @also_not_leaf_node
+ (identifier) @leaf_node
+ (property_identifier) @also_leaf_node
+ `);
+
+ let tokens = [];
+ const original = grammar.idForScope.bind(grammar);
+ grammar.idForScope = function(scope, text) {
+ if (text) {
+ tokens.push(text);
+ }
+ return original(scope, text);
+ };
+
+ const languageMode = new WASMTreeSitterLanguageMode({ grammar, buffer });
+ buffer.setLanguageMode(languageMode);
+ buffer.setText('aa.bb(cc.dd());');
+ await languageMode.ready;
+
+ // If non-leaf nodes are included, this list would included things like
+ // 'aa.bb()' and `cc.dd()`
+ expect(tokens).toEqual([
+ 'aa',
+ 'bb',
+ 'cc',
+ 'dd',
+ ]);
+ });
+
it('interpolates magic tokens in scope names', async () => {
await grammar.setQueryForTest('highlightsQuery', `
(lexical_declaration kind: _ @declaration._TYPE_)
diff --git a/src/scope-resolver.js b/src/scope-resolver.js
index 049b08e0d..1760e4a9d 100644
--- a/src/scope-resolver.js
+++ b/src/scope-resolver.js
@@ -499,7 +499,10 @@ class ScopeResolver {
return false;
}
- let id = this.idForScope(name);
+ let id = this.idForScope(
+ name,
+ node.childCount === 0 ? node.text : undefined,
+ );
let {
startPosition: start,
diff --git a/src/tree-sitter-grammar.js b/src/tree-sitter-grammar.js
index e76b8aed4..794dc79b6 100644
--- a/src/tree-sitter-grammar.js
+++ b/src/tree-sitter-grammar.js
@@ -70,7 +70,9 @@ module.exports = class TreeSitterGrammar {
return `TreeSitterGrammar {scopeName: ${this.scopeName}}`;
}
- idForScope(scopeName) {
+ // Though _text is unused here, some packages (eg semanticolor) use it to
+ // customize scopes on the fly.
+ idForScope(scopeName, _text) {
if (!scopeName) {
return undefined;
}
diff --git a/src/ui.js b/src/ui.js
index 3ee3fc3c6..2a4662c44 100644
--- a/src/ui.js
+++ b/src/ui.js
@@ -292,8 +292,8 @@ function renderMarkdown(content, givenOpts = {}) {
if (match) {
// We define breakline as a custom Token Type
let token = state.push("html_inline", "breakline", 0);
- token.content = "
";
- state.pos += "
".length;
+ token.content = "
";
+ state.pos += match[0].length;
return true;
}
}
diff --git a/src/wasm-tree-sitter-grammar.js b/src/wasm-tree-sitter-grammar.js
index 35182f9a9..fc6c87647 100644
--- a/src/wasm-tree-sitter-grammar.js
+++ b/src/wasm-tree-sitter-grammar.js
@@ -55,7 +55,9 @@ module.exports = class WASMTreeSitterGrammar {
}
}
- idForScope(scopeName) {
+ // Though _text is unused here, some packages (eg semanticolor) use it to
+ // customize scopes on the fly.
+ idForScope(scopeName, _text) {
if (!scopeName) { return undefined; }
let id = this.idsByScope[scopeName];
if (!id) {
diff --git a/src/wasm-tree-sitter-language-mode.js b/src/wasm-tree-sitter-language-mode.js
index 7aa863530..e7e54df13 100644
--- a/src/wasm-tree-sitter-language-mode.js
+++ b/src/wasm-tree-sitter-language-mode.js
@@ -492,8 +492,8 @@ class WASMTreeSitterLanguageMode {
return this.grammar.scopeNameForScopeId(scopeId);
}
- idForScope(name) {
- return this.grammar.idForScope(name);
+ idForScope(name, text) {
+ return this.grammar.idForScope(name, text);
}
// Behaves like `scopeDescriptorForPosition`, but returns a list of
@@ -3016,7 +3016,7 @@ class LanguageLayer {
this.tree = null;
this.scopeResolver = new ScopeResolver(
this,
- (name) => this.languageMode.idForScope(name)
+ (name, text) => this.languageMode.idForScope(name, text)
);
this.foldResolver = new FoldResolver(this.buffer, this);