Merge remote-tracking branch 'origin/master' into clojure-grammar-enhancements

This commit is contained in:
Maurício Szabo 2024-04-30 11:10:27 -03:00
commit a2a6d3e67e
60 changed files with 5923 additions and 1104 deletions

View File

@ -40,10 +40,10 @@ jobs:
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
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
@ -52,7 +52,7 @@ jobs:
# 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
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
@ -101,7 +101,7 @@ jobs:
run: npx node-gyp install ${{ env.NODE_VERSION }}
- name: Install Pulsar Dependencies
uses: nick-fields/retry@943e742917ac94714d2f408a0e8320f2d1fcafcd
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e
with:
timeout_minutes: 30
max_attempts: 3
@ -110,7 +110,7 @@ jobs:
on_retry_command: rm -R node_modules
- name: Build Pulsar
uses: nick-fields/retry@943e742917ac94714d2f408a0e8320f2d1fcafcd
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e
with:
timeout_minutes: 30
max_attempts: 3
@ -121,7 +121,7 @@ jobs:
- name: Cache Pulsar dependencies - Linux
if: ${{ runner.os == 'Linux' }}
uses: actions/cache/save@v3
uses: actions/cache/save@v4
with:
path: |
node_modules
@ -140,7 +140,7 @@ jobs:
APPLEID: ${{ secrets.APPLEID }}
APPLEID_PASSWORD: ${{ secrets.APPLEID_PASSWORD }}
TEAM_ID: ${{ secrets.TEAM_ID }}
uses: nick-fields/retry@943e742917ac94714d2f408a0e8320f2d1fcafcd
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e
with:
timeout_minutes: 45
max_attempts: 3
@ -149,7 +149,7 @@ jobs:
- name: Build Pulsar Binaries (macOS) (Unsigned)
if: ${{ runner.os == 'macOS' && github.event_name != 'push' }}
uses: nick-fields/retry@943e742917ac94714d2f408a0e8320f2d1fcafcd
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e
with:
timeout_minutes: 45
max_attempts: 3
@ -158,7 +158,7 @@ jobs:
- name: Build Pulsar Binaries
if: ${{ runner.os != 'macOS' }}
uses: nick-fields/retry@943e742917ac94714d2f408a0e8320f2d1fcafcd
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e
with:
timeout_minutes: 30
max_attempts: 3
@ -179,13 +179,13 @@ jobs:
- name: Cache Pulsar Binaries - Linux
if: ${{ runner.os == 'Linux' }}
uses: actions/cache/save@v3
uses: actions/cache/save@v4
with:
path: ./binaries
key: pulsar-Linux-Binaries-${{ github.sha }}-${{ github.workflow }}
- name: Upload Binary Artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os }} Binaries
path: ./binaries/*
@ -219,7 +219,7 @@ jobs:
- name: Upload Video Artifacts
# Run whether this job passed or failed, unless explicitly cancelled.
if: ${{ !cancelled() && runner.os != 'Linux' }}
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os }} Videos
path: ./tests/videos/**
@ -235,23 +235,23 @@ jobs:
steps:
- name: Checkout the latest code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore Cached Pulsar Binaries - Linux
if: ${{ runner.os == 'Linux' }}
uses: actions/cache/restore@v3
uses: actions/cache/restore@v4
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
uses: actions/cache/restore@v4
with:
path: |
node_modules
@ -285,7 +285,7 @@ jobs:
- 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
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os }} Videos
path: ./tests/videos/**

View File

@ -20,10 +20,10 @@ jobs:
steps:
- name: Checkout the Latest Code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup NodeJS - ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
@ -43,6 +43,14 @@ jobs:
run: yarn run private-js-docs
- name: Commit All Changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: GH Action Documentation
run: |
if [ -n "`git status -s | grep "^ M"`" ]; then
echo "Uncommitted changes to repo files detected. Committing and pushing now."
git config user.name "${GITHUB_ACTOR}"
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
git add -u
git commit -m "GH Action Documentation"
git push origin HEAD
else
echo "No changes detected in repo files. Nothing to commit!"
fi

View File

@ -21,10 +21,10 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout the latest code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
@ -41,6 +41,9 @@ jobs:
run: yarn build
- name: Run Tests
uses: coactions/setup-xvfb@v1.0.1
with:
run: node script/run-tests.js spec
if: runner.os != 'Linux'
run: node script/run-tests.js spec
- name: Run Tests with xvfb-run (Linux)
if: runner.os == 'Linux'
run: xvfb-run --auto-servernum node script/run-tests.js spec

View File

@ -15,10 +15,10 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout the latest code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
@ -42,14 +42,14 @@ jobs:
- name: Cache pulsar
id: cache-pulsar
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: pulsar.deb
key: pulsar-${{ github.sha }}
- name: Cache dependencies
id: cache-dependencies
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |
node_modules
@ -163,15 +163,15 @@ jobs:
steps:
- name: Checkout the latest code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup NodeJS
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
- name: Restore dependencies from Cache
id: restore-dependencies
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |
node_modules
@ -188,7 +188,7 @@ jobs:
- name: Restore pulsar from Cache
id: restore-pulsar
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: pulsar.deb
key: pulsar-${{ github.sha }}

View File

@ -13,13 +13,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the Latest Code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
# Make sure we get all commits, so that we can compare to early commits
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16

View File

@ -18,6 +18,28 @@
better support for "def" elements (example - don't syntax `default` or
`definition` as a `def`, but highlights `p/defresolver`)
## 1.116.0
* Added `TextEditor::getCommentDelimitersForBufferPosition` for retrieving comment delimiter strings appropriate for a given buffer position. This allows us to support three new snippet variables: `LINE_COMMENT`, `BLOCK_COMMENT_START`, and `BLOCK_COMMENT_END`.
* Added ability to use “simple” transformation flags in snippets (like `/upcase` and `/camelcase`) within `sed`-style snippet transformation replacements.
* Improved TypeScript syntax highlighting of regular expressions, TSX fragments, wildcard export identifiers, namespaced types, and template string punctuation.
* Replaced our underlying Tree-sitter parser for Markdown files with one thats more stable.
* Fixed issues in Python with unwanted indentation after type annotations and applying scope names to constructor functions.
* Removed Machine PATH handling for Pulsar on Windows, ensuring to only ever attempt PATH manipulation per user. Added additional safety mechanisms when handling a user's PATH variable.
* Update (Linux) metainfo from downstream Pulsar Flatpak
### Pulsar
- Updated: Update Pulsar's Linux desktop & metainfo mostly from Flatpak [@cat-master21](https://github.com/pulsar-edit/pulsar/pull/935)
- Updated: [core] Simplify/Cleanup `StyleManager` [@confused-Techie](https://github.com/pulsar-edit/pulsar/pull/959)
- Fixed: Tree-sitter fixes (1.116 edition) [@savetheclocktower](https://github.com/pulsar-edit/pulsar/pull/968)
- Bumped: Bump `snippets` dependency to 1.8.0 [@savetheclocktower](https://github.com/pulsar-edit/pulsar/pull/972)
- Added: Add a `TextEditor` method for retrieving comment delimiters... [@savetheclocktower](https://github.com/pulsar-edit/pulsar/pull/970)
- Fixed: [core] (Windows) Remove all `Machine` PATH handling, add safety mechanisms [@confused-Techie](https://github.com/pulsar-edit/pulsar/pull/957)
### snippets
- Added: Add support for variables `LINE_COMMENT`, `BLOCK_COMMENT_START` and `BLOCK_COMMENT_END` [@savetheclocktower](https://github.com/pulsar-edit/snippets/pull/21)
- Added: Extend support for simple transformation flags to sed-style replacements [@savetheclocktower](https://github.com/pulsar-edit/snippets/pull/20)
## 1.115.0
- Fixed some folds in Ruby like `unless`, some blocks, multiline comments, function calls, and different array syntaxes for strings and keywords.

View File

@ -2,7 +2,7 @@
"name": "pulsar",
"author": "Pulsar-Edit <admin@pulsar-edit.dev>",
"productName": "Pulsar",
"version": "1.115.0-dev",
"version": "1.116.0-dev",
"description": "A Community-led Hyper-Hackable Text Editor",
"branding": {
"id": "pulsar",
@ -159,7 +159,7 @@
"service-hub": "^0.7.4",
"settings-view": "file:packages/settings-view",
"sinon": "9.2.1",
"snippets": "github:pulsar-edit/snippets#6b9163415270b8757b262f5dfaafaa05d47324a9",
"snippets": "github:pulsar-edit/snippets#v1.8.0",
"solarized-dark-syntax": "file:packages/solarized-dark-syntax",
"solarized-light-syntax": "file:packages/solarized-light-syntax",
"spell-check": "file:packages/spell-check",
@ -235,7 +235,7 @@
"package-generator": "file:./packages/package-generator",
"pulsar-updater": "file:./packages/pulsar-updater",
"settings-view": "file:./packages/settings-view",
"snippets": "1.6.1",
"snippets": "1.8.0",
"spell-check": "file:./packages/spell-check",
"status-bar": "file:./packages/status-bar",
"styleguide": "file:./packages/styleguide",

View File

@ -16,6 +16,7 @@ parser: 'tree-sitter-clojure'
'cljx'
'clojure'
'edn'
'bb'
'joke'
'joker'
]

View File

@ -0,0 +1,10 @@
scopeName: 'source.gfm.inline'
type: 'modern-tree-sitter'
parser: 'tree-sitter-markdown_inline'
injectionRegex: '^(markdown-inline-internal)$'
treeSitter:
parserSource: 'github:MDeiml/tree-sitter-markdown/tree-sitter-markdown-inline#28aa3baef73bd458d053b613b8bd10fd102b4405'
grammar: 'tree-sitter-markdown-inline/tree-sitter-markdown-inline.wasm'
highlightsQuery: 'tree-sitter-markdown-inline/highlights.scm'

View File

@ -1,30 +0,0 @@
name: 'GitHub Markdown'
scopeName: 'source.gfm'
type: 'modern-tree-sitter'
# Generated from `savetheclocktower/tree-sitter-frontmatter`.
parser: 'tree-sitter-frontmatter'
treeSitter:
grammar: 'tree-sitter/tree-sitter-frontmatter.wasm'
highlightsQuery: 'tree-sitter/tree-sitter-frontmatter/highlights.scm'
fileTypes: [
'markdown'
'md'
'mdown'
'mdwn'
'mkd'
'mkdn'
'mkdown'
'rmd'
'ron'
'workbook'
]
firstLineRegex: '^---$'
comments:
start: '<!--'
end: '-->'
blockStart: '<!--'
blockEnd: '-->'

View File

@ -1,15 +1,16 @@
# This grammar doesn't have its own name because it's only meant to be injected.
scopeName: 'source.gfm.embedded'
scopeName: 'source.gfm'
type: 'modern-tree-sitter'
name: 'GitHub Markdown'
parser: 'tree-sitter-markdown'
injectionRegex: '(MARKDOWN|markdown|GFM|gfm)$'
injectionRegex: '^(markdown|MARKDOWN|gfm|GFM)$'
treeSitter:
grammar: 'tree-sitter/tree-sitter-markdown.wasm'
highlightsQuery: 'tree-sitter/tree-sitter-markdown/highlights.scm'
foldsQuery: 'tree-sitter/tree-sitter-markdown/folds.scm'
tagsQuery: 'tree-sitter/tree-sitter-markdown/tags.scm'
parserSource: 'github:MDeiml/tree-sitter-markdown/tree-sitter-markdown#28aa3baef73bd458d053b613b8bd10fd102b4405'
grammar: 'tree-sitter-markdown/tree-sitter-markdown.wasm'
highlightsQuery: 'tree-sitter-markdown/highlights.scm'
foldsQuery: 'tree-sitter-markdown/folds.scm'
tagsQuery: 'tree-sitter-markdown/tags.scm'
fileTypes: [
'markdown'

View File

@ -0,0 +1,77 @@
; BOLD/ITALIC/OTHER
; ===============
(emphasis) @markup.italic.gfm
(emphasis
. (emphasis_delimiter) @punctuation.definition.emphasis.begin.gfm)
(emphasis
(emphasis_delimiter) @punctuation.definition.emphasis.end.gfm .)
(strong_emphasis) @markup.bold.gfm
((strong_emphasis) @punctuation.definition.emphasis.begin.gfm
(#set! adjust.endAfterFirstMatchOf "^\\*\\*"))
((strong_emphasis) @punctuation.definition.emphasis.end.gfm
(#set! adjust.startBeforeFirstMatchOf "\\*\\*$"))
(strikethrough) @markup.strike.gfm
((strikethrough) @punctuation.definition.strike.begin.gfm
(#set! adjust.endAfterFirstMatchOf "^~~"))
((strikethrough) @punctuation.definition.strike.end.gfm
(#set! adjust.startBeforeFirstMatchOf "~~$"))
; INLINE/REPLACED
; ===============
((uri_autolink) @markup.underline.link
(#set! adjust.startAfterFirstMatchOf "^<")
(#set! adjust.endBeforeFirstMatchOf ">$"))
((uri_autolink) @punctuation.definition.begin.uri-autolink.gfm
(#set! adjust.endAfterFirstMatchOf "^<"))
((uri_autolink) @punctuation.definition.end.uri-autolink.gfm
(#set! adjust.startBeforeFirstMatchOf ">$"))
((link_text (image (image_description))) @_IGNORE_
(#set! capture.final))
[(link_text) (image_description)] @string.unquoted.gfm @meta.link.text
; The text inside []s in anchors/image syntax.
(full_reference_link
(link_label) @markup.underline.link.gfm
(#set! adjust.startAfterFirstMatchOf "^\\[")
(#set! adjust.endBeforeFirstMatchOf "]$"))
(image
(link_destination) @markup.underline.link.gfm)
(inline_link
(link_destination) @markup.underline.link.gfm)
(link_title) @string.quoted.link-title.gfm
; CODE SPANS
; ==========
(code_span) @meta.embedded.line.inline-code.gfm @markup.raw.inline.gfm
(code_span
. (code_span_delimiter) @punctuation.definition.begin.string.inline-code.gfm)
(code_span
(code_span_delimiter) @punctuation.definition.end.string.inline-code.gfm
.)
; MISC
; ====
(backslash_escape) @constant.character.escape.gfm
(numeric_character_reference) @constant.character.entity.gfm

View File

@ -0,0 +1,11 @@
; Each individual list item can be folded if it's hard-wrapped.
((list_item) @fold
(#set! fold.endAt endPosition)
(#set! fold.adjustToEndOfPreviousRow true))
; Each section represents a heading and all the content underneath it until the
; next heading of equivalent or higher importance.
((section) @fold
(#set! fold.endAt endPosition)
(#set! fold.adjustToEndOfPreviousRow true))

View File

@ -0,0 +1,94 @@
; HEADINGS
; ========
(setext_heading
heading_content: (_) @markup.heading.heading-1.gfm
(setext_h1_underline) @punctuation.definition.heading-underline.gfm)
(setext_heading
heading_content: (_) @markup.heading.heading-2.gfm
(setext_h2_underline) @punctuation.definition.heading-underline.gfm)
(atx_heading
(atx_h1_marker)) @markup.heading.heading-1.gfm
(atx_heading
(atx_h2_marker)) @markup.heading.heading-2.gfm
(atx_heading
(atx_h3_marker)) @markup.heading.heading-3.gfm
(atx_heading
(atx_h4_marker)) @markup.heading.heading-4.gfm
(atx_heading
(atx_h5_marker)) @markup.heading.heading-5.gfm
(atx_heading
(atx_h6_marker)) @markup.heading.heading-6.gfm
; SECTIONS
; ========
(paragraph) @markup.paragraph.gfm
(thematic_break) @markup.horizontal-rule.gfm
(block_quote) @markup.quote.blockquote.gfm
((block_quote_marker) @punctuation.definition.blockquote.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "\\S"))
; LISTS
; =====
(list) @meta.list.gfm
(list_item
(list_marker_dot) @punctuation.definition.list-item.gfm
) @markup.list.numbered
(list_item
[
(list_marker_star)
(list_marker_minus)
(list_marker_plus)
] @punctuation.definition.list-item.gfm
) @markup.list.unnumbered
(task_list_marker_unchecked) @punctuation.definition.task-marker.unchecked.gfm
(task_list_marker_checked) @punctuation.definition.task-marker.unchecked.gfm
; CODE BLOCKS
; ===========
(info_string) @storage.modifier.language._TEXT_.gfm
(fenced_code_block
(code_fence_content) @markup.raw.block.fenced.gfm) @meta.embedded.block.fenced-code.gfm
(indented_code_block) @markup.raw.block.indented.gfm @meta.embedded.block.indented-code.gfm
; MISC
; ====
(pipe_table) @markup.other.table.gfm
(pipe_table_header
(pipe_table_cell) @markup.other.table-cell.header.gfm)
(pipe_table_row
(pipe_table_cell) @markup.other.table-cell.data.gfm)
(pipe_table_delimiter_row
(pipe_table_delimiter_cell
(_) @punctuation.separator.table-row.gfm)
)
; Link definitions
(link_reference_definition
(link_label)
(link_destination) @markup.underline.link.gfm)
((link_label) @meta.link.text
(#set! adjust.offsetStart 1)
(#set! adjust.offsetEnd -1))

View File

@ -0,0 +1,52 @@
; Each heading counts as a tag for symbol navigation purposes. We'll indicate a
; symbol's heading level with a certain number of dots prepended to the symbol
; name.
((atx_heading
(atx_h1_marker)
heading_content: (_) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "· "))
((atx_heading
(atx_h2_marker)
heading_content: (_) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "·· "))
((atx_heading
(atx_h3_marker)
heading_content: (_) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "··· "))
((atx_heading
(atx_h4_marker)
heading_content: (_) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "···· "))
((atx_heading
(atx_h5_marker)
heading_content: (_) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "····· "))
((atx_heading
(atx_h6_marker)
heading_content: (_) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "······ "))
((setext_heading
heading_content: (_) @name) @definition.heading
(setext_h1_underline)
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "· "))
((setext_heading
heading_content: (_) @name) @definition.heading
(setext_h2_underline)
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "·· "))

View File

@ -1 +0,0 @@
(front_matter) @meta.embedded.block.front-matter.gfm

View File

@ -1,22 +0,0 @@
; TODO: Folds in Markdown files will have to wait until we can add "tags" to
; divided folds. We want an H1 section to be able to fold up everything until
; the next H1 in the file, an H2 to fold up everything until the next H2 _or_
; H1, an H3 to fold up everything until the next H3 _or_ H2 _or_ H1… but this
; is not currently possible.
; (atx_heading (atx_h1_marker)) @fold.start.h1 @fold.end.h1 @fold.end.h2 @fold.end.h3 @fold.end.h4 @fold.end.h5 @fold.end.h6
;
; (atx_heading (atx_h2_marker)) @fold.start.h2 @fold.end.h2 @fold.end.h3 @fold.end.h4 @fold.end.h5 @fold.end.h6
;
; (atx_heading (atx_h3_marker)) @fold.start.h3 @fold.end.h3 @fold.end.h4 @fold.end.h5 @fold.end.h6
;
; (atx_heading (atx_h4_marker)) @fold.start.h4 @fold.end.h4 @fold.end.h5 @fold.end.h6
;
; (atx_heading (atx_h5_marker)) @fold.start.h5 @fold.end.h5 @fold.end.h6
;
; (atx_heading (atx_h6_marker)) @fold.start.h6 @fold.end.h6
;
; ; [(atx_heading) (setext_heading)] @fold.end @fold.start
((list_item) @fold
(#set! fold.endAt endPosition))

View File

@ -1,188 +0,0 @@
; HEADINGS
; ========
(setext_heading
(heading_content) @markup.heading.heading-1.gfm
(setext_h1_underline) @punctuation.definition.heading-underline.gfm)
(setext_heading
(heading_content) @markup.heading.heading-2.gfm
(setext_h2_underline) @punctuation.definition.heading-underline.gfm)
(atx_heading
(atx_h1_marker) @punctuation.definition.heading.gfm
) @markup.heading.heading-1.gfm
(atx_heading
(atx_h2_marker) @punctuation.definition.heading.gfm
) @markup.heading.heading-2.gfm
(atx_heading
(atx_h3_marker) @punctuation.definition.heading.gfm
) @markup.heading.heading-3.gfm
(atx_heading
(atx_h4_marker) @punctuation.definition.heading.gfm
) @markup.heading.heading-4.gfm
(atx_heading
(atx_h5_marker) @punctuation.definition.heading.gfm
) @markup.heading.heading-5.gfm
(atx_heading
(atx_h6_marker) @punctuation.definition.heading.gfm
) @markup.heading.heading-6.gfm
; SECTIONS
; ========
(paragraph) @markup.paragraph.gfm
(thematic_break) @markup.horizontal-rule.gfm
(block_quote) @markup.quote.blockquote.gfm
((block_quote) @punctuation.definition.blockquote.gfm
(#set! adjust.endAfterFirstMatchOf ">"))
; LISTS
; =====
; `markup.list` gets applied to individual list items, unintuitively. So let's
; scope the entire list. “Tight” vs “Loose” has to do with whether each `<li>`
; has one or more implicit `<p>` tags around it.
[(tight_list) (loose_list)] @meta.list.gfm
((list_item
(list_marker) @punctuation.definition.list-item.gfm) @markup.list.unnumbered
; Instead of matching bullet or minus or plus, any not-digit here is
; guaranteed to be an unordered list.
(#not-match? @punctuation.definition.list-item.gfm "^\\d"))
((list_item
(list_marker) @punctuation.definition.list-item.gfm) @markup.list.numbered
(#match? @punctuation.definition.list-item.gfm "^\\d"))
((task_list_item
(list_marker) @punctuation.definition.list-item.gfm) @markup.list.unnumbered
; Instead of matching bullet or minus or plus, any not-digit here is
; guaranteed to be an unordered list.
(#not-match? @punctuation.definition.list-item.gfm "^\\d"))
((task_list_item
(list_marker) @punctuation.definition.list-item.gfm) @markup.list.numbered
(#match? @punctuation.definition.list-item.gfm "^\\d"))
; INLINE/REPLACED
; ===============
; The text inside []s in anchors/image syntax.
[(link_text) (image_description)] @string.unquoted.gfm @meta.link.text
(link_label (text) @meta.link.text)
; A URL between ()s in anchor syntax.
(link_destination) @markup.underline.link.gfm
((link) @punctuation.definition.begin.link.bracket.round.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "(?<=\\])\\("))
((link) @punctuation.definition.end.link.bracket.round.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "\\)$"))
((link) @punctuation.definition.begin.link.bracket.square.gfm
(#set! adjust.endAfterFirstMatchOf "^\\["))
((link) @punctuation.definition.end.link.bracket.square.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "\\](?=\\(|\\[)"))
((link_reference_definition) @punctuation.definition.begin.link.bracket.square.gfm
(#set! adjust.endAfterFirstMatchOf "^\\["))
((link_reference_definition) @punctuation.definition.end.link.bracket.square.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "\\](?=\\(|\\[)"))
((link_reference_definition) @punctuation.separator.link.colon.gfm
(#set! adjust.startAndEndAroundFirstMatchOf ":"))
; A URL between <>s in autolink syntax.
(uri_autolink (text) @markup.underline.link.gfm)
((uri_autolink) @punctuation.definition.link.begin.bracket.angle.gfm
(#set! adjust.endAfterFirstMatchOf "^<"))
((uri_autolink) @punctuation.definition.link.end.bracket.angle.gfm
(#set! adjust.startBeforeFirstMatchOf ">$"))
; A link title: `[foo](http://example.com "Example web site")`
((link_title) @string.quoted.double.link-title.gfm
(#match? @string.quoted.double.link-title.gfm "^\"")
(#set! capture.final true))
((link_title) @punctuation.definition.string.begin.gfm
(#match? @punctuation.definition.string.begin.gfm "^\"")
(#set! adjust.endAfterFirstMatchOf "^\""))
((link_title) @punctuation.definition.string.end.gfm
(#match? @punctuation.definition.string.end.gfm "\"$")
(#set! adjust.startBeforeFirstMatchOf "\"$"))
; Out of laziness, let's throw all other kinds of link title into the generic
; bin — they are all delimited _somehow_, right?
(link_title) @string.quoted.link-title.gfm
; Link labels in `[foo][bar]` syntax, where `bar` is associated with a URL via
; a subsequent footnote, actually work correctly when one runs "Link: Open" in
; Pulsar, so these should be treated like links.
(link_label) @markup.underline.link.link-label.gfm
(image) @meta.image.gfm
; CODE BLOCKS
; ===========
(code_span) @meta.embedded.line.inline-code.gfm @markup.raw.inline.gfm
(info_string) @storage.modifier.language._TEXT_.gfm
(fenced_code_block
(code_fence_content) @markup.raw.block.fenced.gfm) @meta.embedded.block.fenced-code.gfm
(indented_code_block) @markup.raw.block.indented.gfm @meta.embedded.block.indented-code.gfm
; BOLD/ITALIC/OTHER
; =================
(emphasis) @markup.italic.gfm
(strong_emphasis) @markup.bold.gfm
(strikethrough) @markup.strike.gfm
((emphasis) @punctuation.delimiter.emphasis.begin.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "^(\\*|_)"))
((emphasis) @punctuation.delimiter.emphasis.end.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "(\\*|_)$"))
((strong_emphasis) @punctuation.delimiter.emphasis.begin.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "^(\\*{2}|_{2})"))
((strong_emphasis) @punctuation.delimiter.emphasis.end.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "(\\*{2}|_{2})$"))
((strikethrough) @punctuation.delimiter.strike.begin.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "^~~"))
((strikethrough) @punctuation.delimiter.strike.begin.gfm
(#set! adjust.startAndEndAroundFirstMatchOf "~~$"))
; HTML
; ====
(html_comment) @comment.block.html
; MISC
; ====
(table) @markup.other.table.gfm
(table_header_row (table_cell) @markup.other.table-cell.header.gfm)
(table_data_row (table_cell) @markup.other.table-cell.data.gfm)
(table_delimiter_row (table_column_alignment) @punctuation.separator.table-row.gfm)
(backslash_escape) @constant.character.escape.gfm

View File

@ -1,3 +0,0 @@
; Intentionally empty indents.scm. By and large, indentation level should be
; manually controlled by the user in Markdown; the best thing we can do is stay
; out of the user's way.

View File

@ -1,56 +0,0 @@
((atx_heading
(atx_h1_marker)
(heading_content) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "· ")
(#set! symbol.icon "chevron-right"))
((atx_heading
(atx_h2_marker)
(heading_content) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "·· ")
(#set! symbol.icon "chevron-right"))
((atx_heading
(atx_h3_marker)
(heading_content) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "··· ")
(#set! symbol.icon "chevron-right"))
((atx_heading
(atx_h4_marker)
(heading_content) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "···· ")
(#set! symbol.icon "chevron-right"))
((atx_heading
(atx_h5_marker)
(heading_content) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "····· ")
(#set! symbol.icon "chevron-right"))
((atx_heading
(atx_h6_marker)
(heading_content) @name) @definition.heading
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "······ ")
(#set! symbol.icon "chevron-right"))
((setext_heading
(heading_content) @name) @definition.heading
(setext_h1_underline)
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "· ")
(#set! symbol.icon "chevron-right"))
((setext_heading
(heading_content) @name) @definition.heading
(setext_h2_underline)
(#set! symbol.strip "(^\\s*|\\s*$)")
(#set! symbol.prepend "·· ")
(#set! symbol.icon "chevron-right"))

View File

@ -1,127 +1,74 @@
exports.activate = () => {
// The top-level tree-sitter parser for `source.gfm` simply divides the text
// into front matter (if it exists) and the remainder, which is directly
// parsed as Markdown.
// Injection for YAML front matter.
//
// We do this because the `ikatyang/tree-sitter-markdown` parser does not
// recognize YAML front matter, but is otherwise a very strong Markdown
// parser. If the `MDeiml/tree-sitter-markdown` parser became more stable,
// we could consider switching, and then we wouldn't need this extra parser.
// Hand off the front matter to the YAML injection.
// TODO: If people want fancy front matter support, like the ability to
// control the front matter description language, then we might try to employ
// the technique we used for the last Markdown parser and use
// `tree-sitter-frontmatter` as the outermost grammar.
atom.grammars.addInjectionPoint('source.gfm', {
type: 'front_matter',
type: 'minus_metadata',
language: () => 'yaml',
content(node) {
return node.descendantsOfType('text');
}
content: (node) => node
});
// Hand off everything else to the Markdown injection.
// This is a two-phase parser. The outer parser handles block-level content;
// the inner parser handles inline content.
atom.grammars.addInjectionPoint('source.gfm', {
type: 'remainder',
language: () => 'markdown',
type: 'inline',
language: () => {
return 'markdown-inline-internal';
},
content: (node) => node,
includeChildren: true,
languageScope: null
});
// The markdown injection has a scope name of `source.gfm.embedded` so we can
// target it for the rest of these injections, but you can see above that we
// suppress that scope name when we inject it into a document.
// Highlight HTML blocks.
atom.grammars.addInjectionPoint('source.gfm.embedded', {
type: 'html_block',
// Create one HTML injection layer for all block-level HTML nodes.
atom.grammars.addInjectionPoint('source.gfm', {
type: 'document',
language: () => 'html',
content(node) {
return node.descendantsOfType('html_block');
},
includeChildren: true
});
// Injections for code blocks.
atom.grammars.addInjectionPoint('source.gfm', {
type: 'fenced_code_block',
language(node) {
let infoString = node.descendantsOfType('language');
if (infoString.length === 0) return undefined;
return infoString[0]?.text;
},
content(node) {
let codeFenceContent = node.descendantsOfType('code_fence_content');
if (codeFenceContent.length === 0) return undefined;
return codeFenceContent[0];
},
includeChildren: true
});
// Another HTML injection for each inline node that covers inline HTML.
atom.grammars.addInjectionPoint('source.gfm.inline', {
type: 'inline',
language(node) {
// Attempt to cut down on the number of injection layers by returning
// `html` here only when there are HTML nodes in the inline tree.
let html = node.descendantsOfType('html_tag');
return html.length > 0 ? 'html' : undefined;
},
content(node) {
return node.descendantsOfType('html_tag');
},
includeChildren: true
});
};
exports.consumeHyperlinkInjection = (hyperlink) => {
hyperlink.addInjectionPoint('source.gfm.inline', {
types: ['inline'],
content: (node) => node,
includeChildren: true
});
for (let nodeType of ['paragraph', 'table_cell']) {
atom.grammars.addInjectionPoint('source.gfm.embedded', {
type: nodeType,
language(node) {
let html = node.descendantsOfType([
'html_open_tag',
'html_close_tag',
'html_self_closing_tag'
]);
if (html.length === 0) { return null; }
return 'html';
},
content(node) {
let html = node.descendantsOfType([
'html_open_tag',
'html_close_tag',
'html_self_closing_tag'
]);
return html;
},
includeChildren: true
});
}
// All code blocks of the form
//
// ```foo
// (code goes here)
// ```
//
// get injections on the theory that some grammar's `injectionRegex` will
// match `foo`.
atom.grammars.addInjectionPoint('source.gfm.embedded', {
type: 'fenced_code_block',
language(node) {
let language = node?.firstNamedChild;
if (language?.type === 'info_string')
return language.text;
return null;
},
content(node) {
return node.descendantsOfType('code_fence_content');
},
languageScope: (grammar) => `${grammar.scopeName}.embedded`,
includeChildren: true
});
};
// Since this parser isn't guaranteed to detect all URLs in paragraphs (see
// https://github.com/pulsar-edit/pulsar/issues/885), we'll inject the
// `hyperlink` parser into `text` nodes in paragraphs when there appear to be
// URLs in them.
exports.consumeHyperlinkInjection = (hyperlink) => {
function textChildren(node) {
let results = [];
for (let i = 0; i < node.namedChildCount; i++) {
let child = node.child(i);
if (child.type === 'text') {
results.push(child);
}
}
return results;
}
hyperlink.addInjectionPoint('source.gfm.embedded', {
types: ['paragraph'],
// Override the language callback so that it doesn't test URLs that are
// already handled in `uri_autolink` nodes.
language(node) {
for (let child of textChildren(node)) {
if (hyperlink.test(child)) {
return 'hyperlink';
}
}
return null;
},
content(node) {
return textChildren(node);
}
});
};

View File

@ -49,7 +49,8 @@ module.exports = {
content(node) {
return options.content ? options.content(node) : node;
},
languageScope: null
languageScope: options.languageScope ?? null,
includeChildren: options.includeChildren ?? false
});
}
},

View File

@ -573,15 +573,27 @@
(export_statement
(identifier) @variable.other.assignment.export.js)
; The "*" in `import * as Foo`
; The "*" in `import * as Foo from 'bar'`
(import_clause
(namespace_import "*" @variable.other.assignment.import.all.js))
; The "Foo" in `import * as Foo`
; The "Foo" in `import * as Foo from 'bar'`
(import_clause
(namespace_import
(identifier) @variable.other.assignment.import.alias.js))
; The "*" in `export * from 'bar'`
(export_statement "*" @variable.other.assignment.export.all.js)
; The "*" in `export * as Foo from 'bar'`
(export_statement
(namespace_export "*" @variable.other.assignment.export.all.js))
; The "*" in `export * as Foo from 'bar'`
(export_statement
(namespace_export
(identifier) @variable.other.assignment.export.alias.js))
; COMMENTS
; ========

View File

@ -37,13 +37,13 @@
(call
function: (identifier) @support.type.constructor.python
(#match? @support.type.constructor.python "^[A-Z][a-z_]+")
(#match? @support.type.constructor.python "^[A-Z][A-Za-z_]+")
(#set! capture.final true))
(call
function: (attribute
attribute: (identifier) @support.type.constructor.python)
(#match? @support.type.constructor.python "^[A-Z][a-z_]+")
(#match? @support.type.constructor.python "^[A-Z][A-Za-z_]+")
(#set! capture.final true))
(call

View File

@ -1,10 +1,16 @@
; Excluding dictionary key/value separators…
(dictionary
(pair ":" @_IGNORE_
(#set! capture.final true)))
(#set! capture.final)))
; …lambda functions…
((lambda ":" @_IGNORE_)
(#set! capture.final true))
(#set! capture.final))
; …and type annotations on function parameters/class members…
(":" @_IGNORE_ . (type) (#set! capture.final))
; …all other colons we encounter hint at upcoming indents.
":" @indent
; When typing out "else" after an "if" statement, tree-sitter-python won't

View File

@ -38,7 +38,7 @@ firstLineRegex: [
# Try to match `bash` exactly, or failing that, anything that ends in `sh`
# (for zsh/fish/etc.).
injectionRegex: '(^(bash|BASH)$|sh^|SH^)'
injectionRegex: '(^(bash|BASH)$|sh$|SH$)'
treeSitter:
parserSource: 'github:tree-sitter/tree-sitter-bash#8df9ea875d557a150d025d3a15b6e6a58624379a'

View File

@ -17,6 +17,18 @@
(namespace_import
(identifier) @variable.other.assignment.import.namespace._LANG_)
; The "*" in `export * from 'bar'`
(export_statement "*" @variable.other.assignment.export.all.js)
; The "*" in `export * as Foo from 'bar'`
(export_statement
(namespace_export "*" @variable.other.assignment.export.all.js))
; The "*" in `export * as Foo from 'bar'`
(export_statement
(namespace_export
(identifier) @variable.other.assignment.export.alias.js))
; The "Foo" in `export { Foo }`
(export_specifier
name: (identifier) @variable.other.assignment.export._LANG_)
@ -395,9 +407,17 @@
; TODO: We could add a special scope name to the entire suite of DOM types, but
; I don't have the strength for that right now.
;
((type_identifier) @support.storage.other.type._LANG_
)
; The "bar" in `const foo: bar.Baz`.
(nested_type_identifier
module: (identifier) @support.storage.other.property._LANG_)
; The "bar" and "thud" in `const foo: bar.thud.Baz`.
(nested_identifier
(identifier) @support.storage.other.property._LANG_
(#is? test.descendantOfType "type_annotation"))
; Any other type identifiers; the "Bar" in `const foo: Bar`.
(type_identifier) @support.storage.other.type._LANG_
; SUPPORT
; =======
@ -739,8 +759,8 @@
; Interpolations inside of template strings.
(template_substitution
"${" @punctuation.definition.template-expression.begin._LANG_
"}" @punctuation.definition.template-expression.end._LANG_
"${" @punctuation.section.embedded.begin._LANG_
"}" @punctuation.section.embedded.end._LANG_
) @meta.embedded.line.interpolation._LANG_
(string
@ -793,6 +813,22 @@
"debugger"
] @keyword.control._TYPE_._LANG_
; REGEX
; =====
(regex) @string.regexp.js
(regex
"/" @punctuation.definition.string.begin.js
(#is? test.first))
(regex
"/" @punctuation.definition.string.end.js
(#is? test.last))
(regex_flags) @keyword.other.js
; OPERATORS
; =========
@ -925,6 +961,10 @@
; All other sorts of blocks.
(statement_block) @meta.block._LANG_
; The entirety of a type annotation, no matter how simple or complex (e.g.,
; `Event`, `foo.Event`, `foo.bar.Event, foo.Event<MethodDispatcherFactory>`).
(type_annotation (_) @meta.type.annotation._LANG_)
; The inside of a parameter definition list.
((formal_parameters) @meta.parameters._LANG_
(#set! adjust.startAt firstChild.endPosition)

View File

@ -28,18 +28,25 @@
(property_identifier) @entity.other.attribute-name.ts.tsx)
; The empty tag used as a shorthand for a fragment: `<>`.
(jsx_fragment) @meta.tag.ts.tsx
((jsx_fragment) @meta.tag.fragment.ts.tsx
(#set! adjust.endAfterFirstMatchOf "^<>"))
; The closing fragment tag: `</>`.
((jsx_fragment) @meta.tag.fragment.ts.tsx
(#set! adjust.startBeforeFirstMatchOf "</>$"))
; (jsx_fragment)
; The slashes in closing tags should not be interpreted as math operators.
(jsx_self_closing_element "/" @punctuation.definition.tag.end.ts.tsx
(#set! capture.final true))
(#set! capture.final))
(jsx_closing_element "/" @punctuation.definition.tag.end.ts.tsx
(#set! capture.final true))
(#set! capture.final))
; All JSX expressions/interpolations within braces.
((jsx_expression) @meta.embedded.block.ts.tsx
(#match? @meta.embedded.block.ts.tsx "\\n")
(#set! capture.final true))
(#set! capture.final))
(jsx_expression) @meta.embedded.line.ts.tsx
@ -55,9 +62,13 @@
"<" @punctuation.definition.tag.begin.ts.tsx
">" @punctuation.definition.tag.end.ts.tsx)
(jsx_fragment
"/" @punctuation.definition.tag.end.ts.tsx
(#set! capture.final))
(jsx_self_closing_element
"<" @punctuation.definition.tag.begin.ts.tsx
(#set! capture.final true))
(#set! capture.final))
((jsx_self_closing_element
; The "/>" in `<Foo />`, extended to cover both anonymous nodes at once.

View File

@ -8,44 +8,43 @@ It is currently enabled for `.markdown`, `.md`, `.mdown`, `.mkd`, `.mkdown`, `.r
## Customize
By default Markdown Preview uses the colors of the active syntax theme. Enable `Use GitHub.com style` in the __package settings__ to make it look closer to how markdown files get rendered on github.com.
By default Markdown Preview uses the colors of the active syntax theme. Enable **Use GitHub.com Style** in the __package settings__ to make it look closer to how markdown files get rendered on github.com.
![markdown-preview GitHub style](https://cloud.githubusercontent.com/assets/378023/10013087/24ccc7ec-6149-11e5-97ea-53a842a715ea.png)
To customize even further, the styling can be overridden in your `styles.less` file. For example:
When **Use GitHub.com Style** is selected, you can further customize the theme of the Markdown preview with the **GitHub.com Style Mode** setting. Since the GitHub website has a light theme and a dark theme, `markdown-preview` allows you to choose which theme to use when previewing your files. By default, it will use whatever mode is preferred by your system, but you can opt into “Light” or “Dark” to force it to use a particular theme.
No matter which theme you use, you can apply further customizations in your `styles.less` file. For example:
```css
.markdown-preview.markdown-preview {
.markdown-preview pre {
background-color: #444;
}
```
## Syntax Highlighting Language Identifier
## Language identifiers in fenced code blocks
While a verbose specification of Markdown, mostly, ensures the content of Markdown will look the same everywhere it's shipped, the same isn't true of code block language identifiers.
A detailed Markdown specification helps to ensure that Markdown is displayed consistently across multiple parsers. Sadly, the same isnt true of code block language identifiers — the strings you use to tell the renderer what sort of code is inside a code block.
A "code block language identifier" is the string you use to tell the Markdown renderer what code is inside a code block of your Markdown document.
The CommonMark specification [explicitly avoids standardizing these identifiers](https://spec.commonmark.org/0.31.2/#info-string):
Nearly every Markdown rendering system supports different strings to specify your language than each other. `Markdown-Preview` has implemented several valid Language Identifier systems to help ensure that your Markdown will look the same no matter where you publish it!
> The first word of the info string is typically used to specify the language of the code sample, and rendered in the class attribute of the code tag. However, this spec does not mandate any particular treatment of the info string.
In the settings, you can select from a list of different popular Language Identification systems that can then be used in your code blocks. This means that they will still be valid when shipping them to whatever platform of your choice.
There are several valid ways to infer specific languages from language identifiers such as `js`, `less`, `coffee`, and `c`. This package supports the following systems, configured via the **Syntax Highlighting Language Identifiers** setting:
Currently, `Markdown-Preview` supports the following:
* [Linguist](https://github.com/github-linguist/linguist): Used by GitHub (previously the default and only language identification system).
* [Chroma](https://github.com/alecthomas/chroma): Used by CodeBerg/Gitea/Hugo/Goldmark.
* [Rouge](https://github.com/rouge-ruby/rouge): Used by GitLab/Jekyll.
* [HighlightJS](https://highlightjs.org/): Used in a number of places, but most relevantly on the [Pulsar Package Registry](https://web.pulsar-edit.dev/) website.
* Linguist: Used by GitHub (Previously the default and only language identification system)
* Chroma: Used by CodeBerg/Gitea/Hugo/Goldmark
* Rouge: Used by GitLab/Jekyll
* HighlightJS: Used by Markdown-IT/Pulsar Package Website
If none of these systems meets your needs, you may specify custom language identifiers. This may not be as portable as the systems described above, but it will at least produce the desired outcome on your own system.
The setting **Custom Syntax Highlighting Language Identifiers** lets you define a list of custom language identifiers that match up to languages available within your Pulsar installation.
Of course, not all Markdown content is destined to be shared, `Markdown-Preview` even lets you specify custom Language Identifiers to be used within your Markdown code blocks.
The setting `Custom Syntax Highlighting Language Identifiers` lets you define a list of custom language identifiers that match up to languages available within your Pulsar installation
For example, if you wanted to highlight your code like JavaScript by just using `j` as your Code Block language Identifier and `p` to use Python Syntax Highlighting, you could add the following to this setting:
For example, if you wanted to map `j` to JavaScript and `p` to Python, youd add the following text to the **Custom Syntax Highlighting Language Identifiers** field:
```
j: source.js, p: source.python
```
And that's it, now anytime you use that language identifier it will be highlighted exactly the way you want. Of course your preference of language identification system will still be used, in addition to your custom list.
Now `markdown-preview` will understand what to do with fenced code blocks that begin with <code>\`\`\`j</code> or <code>\`\`\`p</code>. These custom identifiers will work alongside whatever system youve chosen with **Syntax Highlighting Language Identifiers**, but will supersede that system in the event of conflict.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,448 +0,0 @@
// All of our block level items should have the same margin
@margin: 16px;
// This is styling for generic markdownized text. Anything you put in a
// container with .markdown-body on it should render generally well. It also
// includes some GitHub Flavored Markdown specific styling (like @mentions)
.markdown-body {
overflow: hidden;
font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
font-size: 16px;
line-height: 1.6;
word-wrap: break-word;
> *:first-child {
margin-top: 0 !important;
}
> *:last-child {
margin-bottom: 0 !important;
}
// Anchors like <a name="examples">. These sometimes end up wrapped around
// text when users mistakenly forget to close the tag or use self-closing tag
// syntax. We don't want them to appear like links.
// FIXME: a:not(:link):not(:visited) would be a little clearer here (and
// possibly faster to match), but it breaks styling of <a href> elements due
// to https://bugs.webkit.org/show_bug.cgi?id=142737.
a:not([href]) {
color: inherit;
text-decoration: none;
}
// Link Colors
.absent {
color: #c00;
}
.anchor {
position: absolute;
top: 0;
left: 0;
display: block;
padding-right: 6px;
padding-left: 30px;
margin-left: -30px;
&:focus {
outline: none;
}
}
// Headings
h1, h2, h3, h4, h5, h6 {
position: relative;
margin-top: 1em;
margin-bottom: @margin;
font-weight: bold;
line-height: 1.4;
.octicon-link {
display: none;
color: #000;
vertical-align: middle;
}
&:hover .anchor {
padding-left: 8px;
margin-left: -30px;
text-decoration: none;
.octicon-link {
display: inline-block;
}
}
tt,
code {
font-size: inherit;
}
}
h1 {
padding-bottom: 0.3em;
font-size: 2.25em;
line-height: 1.2;
border-bottom: 1px solid #eee;
.anchor {
line-height: 1;
}
}
h2 {
padding-bottom: 0.3em;
font-size: 1.75em;
line-height: 1.225;
border-bottom: 1px solid #eee;
.anchor {
line-height: 1;
}
}
h3 {
font-size: 1.5em;
line-height: 1.43;
.anchor {
line-height: 1.2;
}
}
h4 {
font-size: 1.25em;
.anchor {
line-height: 1.2;
}
}
h5 {
font-size: 1em;
.anchor {
line-height: 1.1;
}
}
h6 {
font-size: 1em;
color: #777;
.anchor {
line-height: 1.1;
}
}
p,
blockquote,
ul, ol, dl,
table,
pre {
margin-top: 0;
margin-bottom: @margin;
}
hr {
height: 4px;
padding: 0;
margin: @margin 0;
background-color: #e7e7e7;
border: 0 none;
}
// Lists, Blockquotes & Such
ul,
ol {
padding-left: 2em;
&.no-list {
padding: 0;
list-style-type: none;
}
}
// Did someone complain about list spacing? Encourage them
// to create the spacing with their markdown formatting.
// List behavior should be controled by the markup, not the css.
//
// For lists with padding between items, use blank
// lines between items. This will generate paragraphs with
// padding to space things out.
//
// - item
//
// - item
//
// - item
//
// For list without padding, don't use blank lines.
//
// - item
// - item
// - item
//
// Modifying the css to emulate these behaviors merely brakes
// one case in the process of solving another. Don't change
// this unless it's really really a bug.
ul ul,
ul ol,
ol ol,
ol ul {
margin-top: 0;
margin-bottom: 0;
}
li > p {
margin-top: @margin;
}
dl {
padding: 0;
}
dl dt {
padding: 0;
margin-top: @margin;
font-size: 1em;
font-style: italic;
font-weight: bold;
}
dl dd {
padding: 0 @margin;
margin-bottom: @margin;
}
blockquote {
padding: 0 15px;
color: #777;
border-left: 4px solid #ddd;
> :first-child {
margin-top: 0;
}
> :last-child {
margin-bottom: 0;
}
}
// Tables
table {
display: block;
width: 100%;
overflow: auto;
word-break: normal;
word-break: keep-all; // For Firefox to horizontally scroll wider tables.
th {
font-weight: bold;
}
th, td {
padding: 6px 13px;
border: 1px solid #ddd;
}
tr {
background-color: #fff;
border-top: 1px solid #ccc;
&:nth-child(2n) {
background-color: #f8f8f8;
}
}
}
// Images & Stuff
img {
max-width: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.emoji {
max-width: none;
}
// Gollum Image Tags
// Framed
span.frame {
display: block;
overflow: hidden;
& > span {
display: block;
float: left;
width: auto;
padding: 7px;
margin: 13px 0 0;
overflow: hidden;
border: 1px solid #ddd;
}
span img {
display: block;
float: left;
}
span span {
display: block;
padding: 5px 0 0;
clear: both;
color: #333;
}
}
span.align-center {
display: block;
overflow: hidden;
clear: both;
& > span {
display: block;
margin: 13px auto 0;
overflow: hidden;
text-align: center;
}
span img {
margin: 0 auto;
text-align: center;
}
}
span.align-right {
display: block;
overflow: hidden;
clear: both;
& > span {
display: block;
margin: 13px 0 0;
overflow: hidden;
text-align: right;
}
span img {
margin: 0;
text-align: right;
}
}
span.float-left {
display: block;
float: left;
margin-right: 13px;
overflow: hidden;
span {
margin: 13px 0 0;
}
}
span.float-right {
display: block;
float: right;
margin-left: 13px;
overflow: hidden;
& > span {
display: block;
margin: 13px auto 0;
overflow: hidden;
text-align: right;
}
}
// Inline code snippets
code,
tt {
padding: 0;
padding-top: 0.2em;
padding-bottom: 0.2em;
margin: 0;
font-size: 85%;
background-color: rgba(0,0,0,0.04);
border-radius: 3px; // don't add padding, gives scrollbars
&:before,
&:after {
letter-spacing: -0.2em; // this creates padding
content: "\00a0";
}
br { display: none; }
}
del code { text-decoration: inherit; }
// Code tags within code blocks (<pre>s)
pre > code {
padding: 0;
margin: 0;
font-size: 100%;
word-break: normal;
white-space: pre;
background: transparent;
border: 0;
}
.highlight {
margin-bottom: @margin;
}
.highlight pre,
pre {
padding: @margin;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #f7f7f7;
border-radius: 3px;
}
.highlight pre {
margin-bottom: 0;
word-break: normal;
}
pre {
word-wrap: normal;
}
pre code,
pre tt {
display: inline;
max-width: initial;
padding: 0;
margin: 0;
overflow: initial;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
&:before,
&:after {
content: normal;
}
}
kbd {
display: inline-block;
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
color: #555;
vertical-align: middle;
background-color: #fcfcfc;
border: solid 1px #ccc;
border-bottom-color: #bbb;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #bbb;
}
}

View File

@ -13,12 +13,12 @@ function getUserLanguageIds() {
let pairs = usersLanguageIDs.split(",");
for (let i = 0; i < pairs.length; i++) {
let split = pairs[i].split(":");
obj[split[0].trim()] = split[1].trim();
let split = pairs[i].split(":");
obj[split[0].trim()] = split[1].trim();
}
return obj;
} catch(err) {
atom.notifications.addError(`Unable to load Markdown Preview Custom Syntax Highlighting Language Identifiers\n${err.toString()}`);
return {};
@ -61,7 +61,7 @@ function getLanguageIds() {
}
module.exports = {
scopeForFenceName (fenceName) {
scopeForFenceName(fenceName) {
fenceName = fenceName.toLowerCase()
let scopesByFenceName = getLanguageIds();

View File

@ -7,11 +7,11 @@ const fs = require('fs-plus')
const renderer = require('./renderer')
module.exports = class MarkdownPreviewView {
static deserialize (params) {
static deserialize(params) {
return new MarkdownPreviewView(params)
}
constructor ({ editorId, filePath }) {
constructor({ editorId, filePath }) {
this.editorId = editorId
this.filePath = filePath
this.element = document.createElement('div')
@ -34,7 +34,7 @@ module.exports = class MarkdownPreviewView {
}
}
serialize () {
serialize() {
return {
deserializer: 'MarkdownPreviewView',
filePath: this.getPath() != null ? this.getPath() : this.filePath,
@ -42,19 +42,19 @@ module.exports = class MarkdownPreviewView {
}
}
copy () {
copy() {
return new MarkdownPreviewView({
editorId: this.editorId,
filePath: this.getPath() != null ? this.getPath() : this.filePath
})
}
destroy () {
destroy() {
this.disposables.dispose()
this.element.remove()
}
registerScrollCommands () {
registerScrollCommands() {
this.disposables.add(
atom.commands.add(this.element, {
'core:move-up': () => {
@ -79,20 +79,20 @@ module.exports = class MarkdownPreviewView {
)
}
onDidChangeTitle (callback) {
onDidChangeTitle(callback) {
return this.emitter.on('did-change-title', callback)
}
onDidChangeModified (callback) {
onDidChangeModified(callback) {
// No op to suppress deprecation warning
return new Disposable()
}
onDidChangeMarkdown (callback) {
onDidChangeMarkdown(callback) {
return this.emitter.on('did-change-markdown', callback)
}
subscribeToFilePath (filePath) {
subscribeToFilePath(filePath) {
this.file = new File(filePath)
this.emitter.emit('did-change-title')
this.disposables.add(
@ -102,7 +102,7 @@ module.exports = class MarkdownPreviewView {
return this.renderMarkdown()
}
resolveEditor (editorId) {
resolveEditor(editorId) {
const resolve = () => {
this.editor = this.editorForId(editorId)
@ -127,7 +127,7 @@ module.exports = class MarkdownPreviewView {
}
}
editorForId (editorId) {
editorForId(editorId) {
for (const editor of atom.workspace.getTextEditors()) {
if (editor.id != null && editor.id.toString() === editorId.toString()) {
return editor
@ -136,7 +136,7 @@ module.exports = class MarkdownPreviewView {
return null
}
handleEvents () {
handleEvents() {
const lazyRenderMarkdown = _.debounce(() => this.renderMarkdown(), 250)
this.disposables.add(
atom.grammars.onDidAddGrammar(() => lazyRenderMarkdown())
@ -171,11 +171,11 @@ module.exports = class MarkdownPreviewView {
'markdown-preview:reset-zoom': () => {
this.element.style.zoom = 1
},
'markdown-preview:toggle-break-on-single-newline' () {
'markdown-preview:toggle-break-on-single-newline'() {
const keyPath = 'markdown-preview.breakOnSingleNewline'
atom.config.set(keyPath, !atom.config.get(keyPath))
},
'markdown-preview:toggle-github-style' () {
'markdown-preview:toggle-github-style'() {
const keyPath = 'markdown-preview.useGitHubStyle'
atom.config.set(keyPath, !atom.config.get(keyPath))
}
@ -226,10 +226,20 @@ module.exports = class MarkdownPreviewView {
)
)
this.disposables.add(
atom.config.observe('markdown-preview.gitHubStyleMode', gitHubStyleMode => {
this.gitHubStyleMode = gitHubStyleMode
if (this.useGitHubStyle) {
this.element.setAttribute('data-use-github-style', gitHubStyleMode)
}
})
)
this.disposables.add(
atom.config.observe('markdown-preview.useGitHubStyle', useGitHubStyle => {
this.useGitHubStyle = useGitHubStyle
if (useGitHubStyle) {
this.element.setAttribute('data-use-github-style', '')
this.element.setAttribute('data-use-github-style', this.gitHubStyleMode)
} else {
this.element.removeAttribute('data-use-github-style')
}
@ -253,7 +263,7 @@ module.exports = class MarkdownPreviewView {
}
}
renderMarkdown () {
renderMarkdown() {
if (!this.loaded) {
this.showLoading()
}
@ -266,7 +276,7 @@ module.exports = class MarkdownPreviewView {
.catch(reason => this.showError({ message: reason }))
}
getMarkdownSource () {
getMarkdownSource() {
if (this.file && this.file.getPath()) {
return this.file
.read()
@ -287,7 +297,7 @@ module.exports = class MarkdownPreviewView {
}
}
async getHTML () {
async getHTML() {
const source = await this.getMarkdownSource()
if (source == null) {
@ -297,7 +307,7 @@ module.exports = class MarkdownPreviewView {
return renderer.toHTML(source, this.getPath(), this.getGrammar())
}
async renderMarkdownText (text) {
async renderMarkdownText(text) {
const { scrollTop } = this.element
try {
@ -318,7 +328,7 @@ module.exports = class MarkdownPreviewView {
}
}
getTitle () {
getTitle() {
if (this.file != null && this.getPath() != null) {
return `${path.basename(this.getPath())} Preview`
} else if (this.editor != null) {
@ -328,11 +338,11 @@ module.exports = class MarkdownPreviewView {
}
}
getIconName () {
getIconName() {
return 'markdown'
}
getURI () {
getURI() {
if (this.file != null) {
return `markdown-preview://${this.getPath()}`
} else {
@ -340,7 +350,7 @@ module.exports = class MarkdownPreviewView {
}
}
getPath () {
getPath() {
if (this.file != null) {
return this.file.getPath()
} else if (this.editor != null) {
@ -348,16 +358,16 @@ module.exports = class MarkdownPreviewView {
}
}
getGrammar () {
getGrammar() {
return this.editor != null ? this.editor.getGrammar() : undefined
}
getDocumentStyleSheets () {
getDocumentStyleSheets() {
// This function exists so we can stub it
return document.styleSheets
}
getTextEditorStyles () {
getTextEditorStyles() {
const textEditorStyles = document.createElement('atom-styles')
textEditorStyles.initialize(atom.styles)
textEditorStyles.setAttribute('context', 'atom-text-editor')
@ -369,7 +379,7 @@ module.exports = class MarkdownPreviewView {
.map(styleElement => styleElement.innerText)
}
getMarkdownPreviewCSS () {
getMarkdownPreviewCSS() {
const markdownPreviewRules = []
const ruleRegExp = /\.markdown-preview/
const cssUrlRegExp = /url\(atom:\/\/markdown-preview\/assets\/(.*)\)/
@ -401,7 +411,7 @@ module.exports = class MarkdownPreviewView {
})
}
showError (result) {
showError(result) {
this.element.textContent = ''
const h2 = document.createElement('h2')
h2.textContent = 'Previewing Markdown Failed'
@ -413,7 +423,7 @@ module.exports = class MarkdownPreviewView {
}
}
showLoading () {
showLoading() {
this.loading = true
this.element.textContent = ''
const div = document.createElement('div')
@ -422,7 +432,7 @@ module.exports = class MarkdownPreviewView {
this.element.appendChild(div)
}
selectAll () {
selectAll() {
if (this.loading) {
return
}
@ -434,7 +444,7 @@ module.exports = class MarkdownPreviewView {
selection.addRange(range)
}
async copyToClipboard () {
async copyToClipboard() {
if (this.loading) {
return
}
@ -464,7 +474,7 @@ module.exports = class MarkdownPreviewView {
}
}
getSaveDialogOptions () {
getSaveDialogOptions() {
let defaultPath = this.getPath()
if (defaultPath) {
defaultPath += '.html'
@ -479,7 +489,7 @@ module.exports = class MarkdownPreviewView {
return { defaultPath }
}
async saveAs (htmlFilePath) {
async saveAs(htmlFilePath) {
if (this.loading) {
atom.notifications.addWarning(
'Please wait until the Markdown Preview has finished loading before saving'
@ -504,7 +514,7 @@ module.exports = class MarkdownPreviewView {
<title>${title}</title>
<style>${this.getMarkdownPreviewCSS()}</style>
</head>
<body class='markdown-preview' data-use-github-style>${htmlBody}</body>
<body class='markdown-preview' data-use-github-style="${this.gitHubStyleMode}">${htmlBody}</body>
</html>` + '\n' // Ensure trailing newline
fs.writeFileSync(htmlFilePath, html)

View File

@ -0,0 +1,651 @@
{
"name": "markdown-preview",
"version": "0.160.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "markdown-preview",
"version": "0.160.2",
"license": "MIT",
"dependencies": {
"cheerio": "^1.0.0-rc.3",
"dedent": "^1.5.3",
"dompurify": "^2.0.17",
"emoji-images": "^0.1.1",
"fs-plus": "^3.0.0",
"github-markdown-css": "^5.5.1",
"marked": "5.0.3",
"underscore-plus": "^1.0.0",
"yaml-front-matter": "^4.1.1"
},
"devDependencies": {
"temp": "^0.8.1"
},
"engines": {
"atom": "*"
}
},
"node_modules/@types/node": {
"version": "11.13.7",
"license": "MIT"
},
"node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/async": {
"version": "1.5.2",
"license": "MIT"
},
"node_modules/balanced-match": {
"version": "1.0.0",
"license": "MIT"
},
"node_modules/boolbase": {
"version": "1.0.0",
"license": "ISC"
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/cheerio": {
"version": "1.0.0-rc.3",
"license": "MIT",
"dependencies": {
"css-select": "~1.2.0",
"dom-serializer": "~0.1.1",
"entities": "~1.1.1",
"htmlparser2": "^3.9.1",
"lodash": "^4.15.0",
"parse5": "^3.0.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/commander": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
"engines": {
"node": ">= 6"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"license": "MIT"
},
"node_modules/css-select": {
"version": "1.2.0",
"license": "BSD-like",
"dependencies": {
"boolbase": "~1.0.0",
"css-what": "2.1",
"domutils": "1.5.1",
"nth-check": "~1.0.1"
}
},
"node_modules/css-what": {
"version": "2.1.3",
"license": "BSD-2-Clause",
"engines": {
"node": "*"
}
},
"node_modules/dedent": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
"integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==",
"peerDependencies": {
"babel-plugin-macros": "^3.1.0"
},
"peerDependenciesMeta": {
"babel-plugin-macros": {
"optional": true
}
}
},
"node_modules/dom-serializer": {
"version": "0.1.1",
"license": "MIT",
"dependencies": {
"domelementtype": "^1.3.0",
"entities": "^1.1.1"
}
},
"node_modules/domelementtype": {
"version": "1.3.1",
"license": "BSD-2-Clause"
},
"node_modules/domhandler": {
"version": "2.4.2",
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "1"
}
},
"node_modules/dompurify": {
"version": "2.4.7",
"license": "(MPL-2.0 OR Apache-2.0)"
},
"node_modules/domutils": {
"version": "1.5.1",
"dependencies": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"node_modules/emoji-images": {
"version": "0.1.1"
},
"node_modules/entities": {
"version": "1.1.2",
"license": "BSD-2-Clause"
},
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/fs-plus": {
"version": "3.1.1",
"license": "MIT",
"dependencies": {
"async": "^1.5.2",
"mkdirp": "^0.5.1",
"rimraf": "^2.5.2",
"underscore-plus": "1.x"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"license": "ISC"
},
"node_modules/github-markdown-css": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-5.5.1.tgz",
"integrity": "sha512-2osyhNgFt7DEHnGHbgIifWawAqlc68gjJiGwO1xNw/S48jivj8kVaocsVkyJqUi3fm7fdYIDi4C6yOtcqR/aEQ==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/glob": {
"version": "7.1.3",
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
}
},
"node_modules/htmlparser2": {
"version": "3.10.1",
"license": "MIT",
"dependencies": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"license": "ISC",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.3",
"license": "ISC"
},
"node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"license": "MIT"
},
"node_modules/marked": {
"version": "5.0.3",
"license": "MIT",
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/minimatch": {
"version": "3.0.4",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/minimist": {
"version": "0.0.8",
"license": "MIT"
},
"node_modules/mkdirp": {
"version": "0.5.1",
"license": "MIT",
"dependencies": {
"minimist": "0.0.8"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/nth-check": {
"version": "1.0.2",
"license": "BSD-2-Clause",
"dependencies": {
"boolbase": "~1.0.0"
}
},
"node_modules/once": {
"version": "1.4.0",
"license": "ISC",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/parse5": {
"version": "3.0.3",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/readable-stream": {
"version": "3.3.0",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/rimraf": {
"version": "2.6.3",
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"license": "MIT"
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
},
"node_modules/string_decoder": {
"version": "1.2.0",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/temp": {
"version": "0.8.4",
"dev": true,
"license": "MIT",
"dependencies": {
"rimraf": "~2.6.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/underscore": {
"version": "1.13.1",
"license": "MIT"
},
"node_modules/underscore-plus": {
"version": "1.7.0",
"dependencies": {
"underscore": "^1.9.1"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"license": "MIT"
},
"node_modules/wrappy": {
"version": "1.0.2",
"license": "ISC"
},
"node_modules/yaml-front-matter": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/yaml-front-matter/-/yaml-front-matter-4.1.1.tgz",
"integrity": "sha512-ULGbghCLsN8Hs8vfExlqrJIe8Hl2TUjD7/zsIGMP8U+dgRXEsDXk4yydxeZJgdGiimP1XB7zhmhOB4/HyfqOyQ==",
"dependencies": {
"commander": "^6.2.0",
"js-yaml": "^3.14.1"
},
"bin": {
"yaml-front-matter": "bin/js-yaml-front.js"
}
}
},
"dependencies": {
"@types/node": {
"version": "11.13.7"
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"requires": {
"sprintf-js": "~1.0.2"
}
},
"async": {
"version": "1.5.2"
},
"balanced-match": {
"version": "1.0.0"
},
"boolbase": {
"version": "1.0.0"
},
"brace-expansion": {
"version": "1.1.11",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"cheerio": {
"version": "1.0.0-rc.3",
"requires": {
"css-select": "~1.2.0",
"dom-serializer": "~0.1.1",
"entities": "~1.1.1",
"htmlparser2": "^3.9.1",
"lodash": "^4.15.0",
"parse5": "^3.0.1"
}
},
"commander": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="
},
"concat-map": {
"version": "0.0.1"
},
"css-select": {
"version": "1.2.0",
"requires": {
"boolbase": "~1.0.0",
"css-what": "2.1",
"domutils": "1.5.1",
"nth-check": "~1.0.1"
}
},
"css-what": {
"version": "2.1.3"
},
"dedent": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
"integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==",
"requires": {}
},
"dom-serializer": {
"version": "0.1.1",
"requires": {
"domelementtype": "^1.3.0",
"entities": "^1.1.1"
}
},
"domelementtype": {
"version": "1.3.1"
},
"domhandler": {
"version": "2.4.2",
"requires": {
"domelementtype": "1"
}
},
"dompurify": {
"version": "2.4.7"
},
"domutils": {
"version": "1.5.1",
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"emoji-images": {
"version": "0.1.1"
},
"entities": {
"version": "1.1.2"
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"fs-plus": {
"version": "3.1.1",
"requires": {
"async": "^1.5.2",
"mkdirp": "^0.5.1",
"rimraf": "^2.5.2",
"underscore-plus": "1.x"
}
},
"fs.realpath": {
"version": "1.0.0"
},
"github-markdown-css": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-5.5.1.tgz",
"integrity": "sha512-2osyhNgFt7DEHnGHbgIifWawAqlc68gjJiGwO1xNw/S48jivj8kVaocsVkyJqUi3fm7fdYIDi4C6yOtcqR/aEQ=="
},
"glob": {
"version": "7.1.3",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"htmlparser2": {
"version": "3.10.1",
"requires": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
},
"inflight": {
"version": "1.0.6",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.3"
},
"js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"lodash": {
"version": "4.17.21"
},
"marked": {
"version": "5.0.3"
},
"minimatch": {
"version": "3.0.4",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8"
},
"mkdirp": {
"version": "0.5.1",
"requires": {
"minimist": "0.0.8"
}
},
"nth-check": {
"version": "1.0.2",
"requires": {
"boolbase": "~1.0.0"
}
},
"once": {
"version": "1.4.0",
"requires": {
"wrappy": "1"
}
},
"parse5": {
"version": "3.0.3",
"requires": {
"@types/node": "*"
}
},
"path-is-absolute": {
"version": "1.0.1"
},
"readable-stream": {
"version": "3.3.0",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"rimraf": {
"version": "2.6.3",
"requires": {
"glob": "^7.1.3"
}
},
"safe-buffer": {
"version": "5.1.2"
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
},
"string_decoder": {
"version": "1.2.0",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"temp": {
"version": "0.8.4",
"dev": true,
"requires": {
"rimraf": "~2.6.2"
}
},
"underscore": {
"version": "1.13.1"
},
"underscore-plus": {
"version": "1.7.0",
"requires": {
"underscore": "^1.9.1"
}
},
"util-deprecate": {
"version": "1.0.2"
},
"wrappy": {
"version": "1.0.2"
},
"yaml-front-matter": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/yaml-front-matter/-/yaml-front-matter-4.1.1.tgz",
"integrity": "sha512-ULGbghCLsN8Hs8vfExlqrJIe8Hl2TUjD7/zsIGMP8U+dgRXEsDXk4yydxeZJgdGiimP1XB7zhmhOB4/HyfqOyQ==",
"requires": {
"commander": "^6.2.0",
"js-yaml": "^3.14.1"
}
}
}
}

View File

@ -8,11 +8,16 @@
"engines": {
"atom": "*"
},
"scripts": {
"generate-github-markdown-css": "node scripts/generate-github-markdown-css.js"
},
"dependencies": {
"cheerio": "^1.0.0-rc.3",
"dedent": "^1.5.3",
"dompurify": "^2.0.17",
"emoji-images": "^0.1.1",
"fs-plus": "^3.0.0",
"github-markdown-css": "^5.5.1",
"marked": "5.0.3",
"underscore-plus": "^1.0.0",
"yaml-front-matter": "^4.1.1"
@ -26,25 +31,30 @@
"configSchema": {
"breakOnSingleNewline": {
"type": "boolean",
"order": 1,
"default": false,
"description": "In Markdown, a single newline character doesn't cause a line break in the generated HTML. In GitHub Flavored Markdown, that is not true. Enable this config option to insert line breaks in rendered HTML for single newlines in Markdown source."
},
"liveUpdate": {
"type": "boolean",
"order": 2,
"default": true,
"description": "Re-render the preview as the contents of the source changes, without requiring the source buffer to be saved. If disabled, the preview is re-rendered only when the buffer is saved to disk."
},
"openPreviewInSplitPane": {
"order": 3,
"type": "boolean",
"default": true,
"description": "Open the preview in a split pane. If disabled, the preview is opened in a new tab in the same pane."
},
"allowUnsafeProtocols": {
"order": 4,
"type": "boolean",
"default": false,
"description": "Allow HTML attributes to use protocols normally considered unsafe such as `file://` and absolute paths on Windows."
},
"grammars": {
"order": 0,
"type": "array",
"default": [
"source.gfm",
@ -57,12 +67,36 @@
"description": "List of scopes for languages for which previewing is enabled. See [this README](https://github.com/pulsar-edit/spell-check#readme) for more information on finding the correct scope for a specific language."
},
"useGitHubStyle": {
"title": "Use GitHub.com style",
"order": 5,
"title": "Use GitHub.com Style",
"type": "boolean",
"default": false,
"description": "Use the same CSS styles for preview as the ones used on GitHub.com."
},
"gitHubStyleMode": {
"order": 6,
"title": "GitHub.com Style Mode",
"type": "string",
"default": "auto",
"description": "Whether to use light-mode GitHub CSS, dark-mode GitHub CSS, or system default (based on your operating system preferences). Has no effect unless **Use GitHub.com Style** is enabled.",
"enum": [
{
"value": "auto",
"description": "System Default"
},
{
"value": "light",
"description": "Light"
},
{
"value": "dark",
"description": "Dark"
}
]
},
"syntaxHighlightingLanguageIdentifier": {
"order": 7,
"title": "Syntax Highlighting Language Identifiers",
"description": "Syntax Highlighting System to use for code block language identification. See [the README](https://github.com/pulsar-edit/pulsar/tree/master/packages/markdown-preview#readme) for details.",
"type": "string",
"default": "linguist",
@ -86,14 +120,14 @@
]
},
"customSyntaxHighlightingLanguageIdentifiers": {
"description": "Custom comma seperated list of Syntax Language Identifiers to map to any language. See [the README](https://github.com/pulsar-edit/pulsar/tree/master/packages/markdown-preview#readme) for usage.",
"description": "Comma-separated list of syntax language identifiers to map to any language. See [the README](https://github.com/pulsar-edit/pulsar/tree/master/packages/markdown-preview#readme) for usage.",
"type": "string",
"default": ""
},
"useOriginalParser": {
"description": "Wether to use the original Markdown Parser, or the new Pulsar one.",
"description": "When checked, will use the original Markdown parser for `markdown-preview` (`marked`). When unchecked, will use the new Markdown parser built into Pulsar (`markdown-it`).",
"type": "boolean",
"default": "true"
"default": true
}
}
}

View File

@ -0,0 +1,38 @@
// Run this script whenever the `github-markdown-css` dependency is updated in
// order to regenerate GitHub styles.
const fs = require('fs/promises');
const path = require('path');
const dedent = require('dedent');
const ASSETS = path.resolve(__dirname, '..', 'assets')
const ASSET_LIGHT = require.resolve('github-markdown-css/github-markdown-light.css')
const ASSET_DARK = require.resolve('github-markdown-css/github-markdown-dark.css')
async function run() {
let lightContents = (await fs.readFile(ASSET_LIGHT)).toString();
let darkContents = (await fs.readFile(ASSET_DARK)).toString();
let lightCSSAuto = lightContents.replace(/\.markdown-body\b/g, '.markdown-preview[data-use-github-style="auto"]');
let darkCSSAuto = darkContents.replace(/\.markdown-body\b/g, '.markdown-preview[data-use-github-style="auto"]');
const autoCSSMode = dedent`
@media (prefers-color-scheme: light) {
${lightCSSAuto}
}
@media (prefers-color-scheme: dark) {
${darkCSSAuto}
}
`;
let lightCSSMode = lightContents.replace(/\.markdown-body\b/g, '.markdown-preview[data-use-github-style="light"]');
let darkCSSMode = darkContents.replace(/\.markdown-body\b/g, '.markdown-preview[data-use-github-style="dark"]');
await fs.writeFile(path.join(ASSETS, 'github-markdown-auto.css'), autoCSSMode);
await fs.writeFile(path.join(ASSETS, 'github-markdown-light.css'), lightCSSMode);
await fs.writeFile(path.join(ASSETS, 'github-markdown-dark.css'), darkCSSMode);
}
run()

View File

@ -0,0 +1,12 @@
{
"env": { "jasmine": true },
"rules": {
"node/no-unpublished-require": "off",
"node/no-extraneous-require": "off",
"no-unused-vars": "off",
"no-empty": "off"
},
"globals": {
"waitsForPromise": true
}
}

View File

@ -722,7 +722,7 @@ world\
expectPreviewInSplitPane()
runs(() =>
expect(preview.element.getAttribute('data-use-github-style')).toBe('')
expect(preview.element.getAttribute('data-use-github-style')).toBe('auto')
)
})

View File

@ -601,4 +601,39 @@ enc\
})
})
})
describe('when GitHub styles are enabled', () => {
beforeEach(() => {
atom.config.set('markdown-preview.useGitHubStyle', true)
atom.config.set('markdown-preview.gitHubStyleMode', 'light')
})
it('uses the GitHub styles', () => {
jasmine.attachToDOM(preview.element)
// It's possible that these values will need to change when the GitHub
// CSS is updated.
const expectedColors = {
light: `rgb(31, 35, 40)`,
dark: `rgb(230, 237, 243)`
}
waitsForPromise(() => preview.renderMarkdown())
// Perform some basic sanity checks about these modes.
expect(preview.element.dataset.useGithubStyle).toBe('light')
let paragraph = preview.element.querySelector('p')
expect(getComputedStyle(paragraph).color).toBe(expectedColors.light)
atom.config.set('markdown-preview.gitHubStyleMode', 'dark')
expect(preview.element.dataset.useGithubStyle).toBe('dark')
expect(getComputedStyle(paragraph).color).toBe(expectedColors.dark)
atom.config.set('markdown-preview.gitHubStyleMode', 'auto')
expect(preview.element.dataset.useGithubStyle).toBe('auto')
// We don't know which mode will be preferred on the system we're running
// on, but as a sanity check we can at least verify that the style value
// is one of the two values we just asserted.
expect([expectedColors.light, expectedColors.dark]).toContain(getComputedStyle(paragraph).color)
})
})
})

View File

@ -1,33 +1,44 @@
// GitHub.com styles
// These are the GitHub Flavored Markdown styles also found on github.com.
// They can be anabled in the markdown-preview settings by turning on "Use GitHub.com styles".
// These are the GitHub Flavored Markdown styles also found on github.com. They
// can be enabled in the `markdown-preview` settings by turning on "Use
// GitHub.com Styles."
//
// We define styles for both dark mode and light mode. A specific mode can be
// opted into via the “GitHub.com Style Mode” setting… or else the user can
// leave the setting on “System Default” to use whatever mode the OS has
// decided to use.
@import (reference) "../assets/primer-markdown";
// The GitHub styles are imported from the `github-markdown-css` package, then
// customized via the `generate-github-markdown-css` task and written to the
// `assets` directory. The task applies some simple transformations to the CSS
// and handles the light-mode/dark-mode logic.
//
// We import these files as `less` files (even though they're ordinary CSS)
// because that forces Less to process them instead of leaving them for the
// standard `@import` directive in CSS. Less can resolve these relative paths,
// but CSS can't.
@import (less) "../assets/github-markdown-auto.css";
@import (less) "../assets/github-markdown-light.css";
@import (less) "../assets/github-markdown-dark.css";
.markdown-preview[data-use-github-style] {
// After we import these rules, we define some overrides; these are needed
// because some UI theme style rules could bleed into Markdown preview areas in
// situations where GitHub relies on browser defaults or fails to envision the
// presence of other possible style rules. Since we don't know what rules the
// user's UI theme has defined, we need to be a bit more paranoid.
// Includes GitHub.com styles from `../assets/primer-markdown.less`.
// Source: https://github.com/primer/primer/tree/master/modules/primer-markdown
.markdown-body();
// The styles below override/complement the GitHub.com styles
// It's needed because some markup or global styles are different
// Overrides for all themes.
.markdown-preview-additions() {
padding: 30px;
font-size: 16px;
color: #333;
background-color: #fff;
overflow: scroll;
a {
color: #337ab7;
}
code {
color: inherit;
border: inherit;
}
atom-text-editor {
@ -37,4 +48,45 @@
border-radius: 4px;
overflow: auto;
}
}
// Overrides for dark mode.
.markdown-preview-additions-dark() {
.markdown-preview-additions();
color: rgb(230, 237, 243);
background-color: rgb(13, 17, 23);
a {
color: rgb(69, 147, 248);
}
}
// Overrides for light mode.
.markdown-preview-additions-light() {
.markdown-preview-additions();
color: rgb(31, 35, 40);
background-color: rgb(255, 255, 255);
a {
color: rgb(11, 105, 218);
}
}
.markdown-preview[data-use-github-style="light"] {
.markdown-preview-additions-light();
}
@media (prefers-color-scheme: light) {
.markdown-preview[data-use-github-style="auto"] {
.markdown-preview-additions-light();
}
}
.markdown-preview[data-use-github-style="dark"] {
.markdown-preview-additions-dark();
}
@media (prefers-color-scheme: dark) {
.markdown-preview[data-use-github-style="auto"] {
.markdown-preview-additions-dark();
}
}

View File

@ -50,22 +50,25 @@ export default class ChangeLogView {
<p>Feel free to read our <a href="https://github.com/pulsar-edit/pulsar/blob/master/CHANGELOG.md">Full Change Log</a>.</p>
<ul>
<li>
Fixed some folds in Ruby like <code>unless</code>, some blocks, multiline comments, function calls, and different array syntaxes for strings and keywords.
Added <code>TextEditor::getCommentDelimitersForBufferPosition</code> for retrieving comment delimiter strings appropriate for a given buffer position. This allows us to support three new snippet variables: <code>LINE_COMMENT</code>, <code>BLOCK_COMMENT_START</code>, and <code>BLOCK_COMMENT_END</code>.
</li>
<li>
Improved the accuracy of indentation hinting in modern Tree-sitter grammars, especially in multi-cursor scenarios.
Added ability to use simple transformation flags in snippets (like <code>/upcase</code> and <code>/camelcase</code>) within <code>sed</code>-style snippet transformation replacements.
</li>
<li>
Improved the ability of the user to opt into a specific kind of grammar for a specific language.
Improved TypeScript syntax highlighting of regular expressions, TSX fragments, wildcard export identifiers, namespaced types, and template string punctuation.
</li>
<li>
Changed the behavior of the <code>grammar-selector</code> package so that it will show the user's preferred grammar for a specific language.
Replaced our underlying Tree-sitter parser for Markdown files with one thats more stable.
</li>
<li>
Updated to version <code>0.20.9</code> of <code>web-tree-sitter</code>.
Fixed issues in Python with unwanted indentation after type annotations and applying scope names to constructor functions.
</li>
<li>
Improved syntax highlighting, indentation, and code folding in various languages, including TypeScript, shell scripts, Ruby, and C/C++.
Removed Machine PATH handling for Pulsar on Windows, ensuring to only ever attempt PATH manipulation per user. Added additional safety mechanisms when handling a user's PATH variable.
</li>
<li>
Update (Linux) metainfo from downstream Pulsar Flatpak
</li>
</ul>

View File

@ -3,22 +3,43 @@
<id>dev.pulsar_edit.Pulsar</id>
<name>Pulsar</name>
<developer_name>Pulsar Edit</developer_name>
<summary>A Community-led Hyper-Hackable Text Editor</summary>
<developer id="dev.pulsar_edit">
<name translatable="no">Pulsar Edit</name>
</developer>
<summary>Community-led hyper-hackable editor</summary>
<launchable type="desktop-id">dev.pulsar_edit.Pulsar.desktop</launchable>
<metadata_license>MIT</metadata_license>
<project_license>MIT</project_license>
<url type="homepage">https://pulsar-edit.dev</url>
<url type="bugtracker">https://github.com/pulsar-edit/pulsar/issues/</url>
<url type="faq">https://pulsar-edit.dev/docs/launch-manual/sections/faq/</url>
<url type="vcs-browser">https://github.com/pulsar-edit/pulsar</url>
<url type="donation">https://pulsar-edit.dev/donate.html</url>
<branding>
<color type="primary" scheme_preference="light">#c061cb</color>
<color type="primary" scheme_preference="dark">#613583</color>
</branding>
<update_contact>admin@pulsar-edit.dev</update_contact>
<description>
<p>Pulsar aims to not only reach feature parity with the original Atom, but to bring Pulsar into the 21st century by updating the underlying architecture, and supporting modern features.</p>
</description>
<screenshots>
<screenshot type="default">
<image type="source">https://raw.githubusercontent.com/pulsar-edit/pulsar/master/resources/linux/linux-screenshot.png</image>
<caption>Pulsar welcome window in the middle, an open file on the right, and project on the left</caption>
</screenshot>
<screenshot>
<image type="source">https://raw.githubusercontent.com/pulsar-edit/pulsar/master/resources/readme.png</image>
<caption>Pulsar welcome window with an open project</caption>
</screenshot>
</screenshots>
<keywords>
<keyword>atom</keyword>
</keywords>
<releases>
</releases>
<kudos>
<kudo>HiDpiIcon</kudo>
</kudos>
<content_rating type="oars-1.1" />
<content_rating type="oars-1.1"/>
</component>

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

View File

@ -6,6 +6,11 @@ Exec=env ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT=false <%= installDir %>/bin/<
Icon=<%= iconPath %>
Type=Application
StartupNotify=true
Categories=GTK;Utility;TextEditor;Development;
MimeType=application/javascript;application/json;application/x-httpd-eruby;application/x-httpd-php;application/x-httpd-php3;application/x-httpd-php4;application/x-httpd-php5;application/x-ruby;application/x-bash;application/x-csh;application/x-sh;application/x-zsh;application/x-shellscript;application/x-sql;application/x-tcl;application/xhtml+xml;application/xml;application/xml-dtd;application/xslt+xml;text/coffeescript;text/css;text/html;text/plain;text/xml;text/xml-dtd;text/x-bash;text/x-c++;text/x-c++hdr;text/x-c++src;text/x-c;text/x-chdr;text/x-csh;text/x-csrc;text/x-dsrc;text/x-diff;text/x-go;text/x-java;text/x-java-source;text/x-makefile;text/x-markdown;text/x-objc;text/x-perl;text/x-php;text/x-python;text/x-ruby;text/x-sh;text/x-zsh;text/yaml;inode/directory
Categories=Utility;TextEditor;Development;
MimeType=application/javascript;application/json;application/x-httpd-eruby;application/x-httpd-php;application/x-httpd-php3;application/x-httpd-php4;application/x-httpd-php5;application/x-ruby;application/x-bash;application/x-csh;application/x-sh;application/x-zsh;application/x-shellscript;application/x-sql;application/x-tcl;application/xhtml+xml;application/xml;application/xml-dtd;application/x-zerosize;application/xslt+xml;text/coffeescript;text/css;text/html;text/plain;text/xml;text/xml-dtd;text/x-bash;text/x-c++;text/x-c++hdr;text/x-c++src;text/x-c;text/x-chdr;text/x-csh;text/x-csrc;text/x-dsrc;text/x-diff;text/x-go;text/x-java;text/x-java-source;text/x-makefile;text/x-markdown;text/x-objc;text/x-perl;text/x-php;text/x-python;text/x-ruby;text/x-sh;text/x-zsh;text/yaml;inode/directory
StartupWMClass=pulsar
Actions=new-window
[Desktop Action new-window]
Name=New Window
Exec=pulsar --new-window

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 128 128">
<circle cx="64" cy="64" r="60" fill="#662d91" stroke-width="0"/>
<g>
<circle cx="64" cy="64" r="9.6" fill="#fff" stroke-width="0"/>
<path d="M53.1,72.3c-.6,0-1.3.3-1.8.8-.8.8-1,1.9-.6,2.8l-5.2,2-21.4,25.5.5.5,25.5-21.4,2-5.2c.3.1.6.2,1,.2.6,0,1.3-.3,1.8-.8,1-1,1-2.6,0-3.6-.5-.5-1.1-.7-1.8-.7h0Z" fill="#fff" stroke-width="0"/>
<path d="M49,100.3c2.4,0,5-.3,7.7-.9,9.4-2.1,18.9-7.7,27-15.8,5.4-5.4,9.8-11.6,12.7-18l-2.5-2.4-.2.5v.3c-2.9,6.1-7,12.1-12.3,17.3-7.6,7.6-16.7,12.9-25.4,14.9-6.5,1.5-12.3,1-16.7-1.5l-2.6,2.2c3.5,2.2,7.6,3.3,12.4,3.3h0Z" fill="#fff" stroke-width="0"/>
<path d="M58.8,90.9c-3-1.7-5.3-3.4-8-5.7l-2.5,2.1c2.2,1.9,4.5,3.6,6.9,5.2.9-.3,2.8-1.1,3.6-1.6h0Z" fill="#fff" stroke-width="0"/>
<path d="M77.8,45.6l-2,5.2c-.3-.1-.6-.2-1-.2-.6,0-1.3.3-1.8.8-1,1-1,2.6,0,3.6.5.5,1.1.8,1.8.8s1.3-.3,1.8-.8c.8-.8,1-1.9.6-2.8l5.2-2,21.4-25.5-.5-.5-25.6,21.4Z" fill="#fff" stroke-width="0"/>
<path d="M49.5,71.2c.2-.2.3-.3.5-.4-1-2.1-1.6-4.3-1.6-6.8,0-8.6,7-15.5,15.5-15.5s4.7.6,6.8,1.6c.2-.2.3-.4.4-.5.8-.8,1.8-1.3,2.9-1.4l.4-1.1c-3.1-1.9-6.7-3-10.5-3-11.1,0-20.1,9-20.1,20.1s1.1,7.5,3,10.5l1.1-.4c.2-1.1.7-2.2,1.5-3h0Z" fill="#fff" stroke-width="0"/>
<path d="M78.5,56.7c-.2.2-.3.3-.5.4,1,2.1,1.6,4.3,1.6,6.8,0,8.6-7,15.5-15.5,15.5s-4.7-.6-6.8-1.6c-.2.2-.3.4-.4.5-.8.8-1.8,1.3-2.9,1.4l-.4,1.1c3.1,1.9,6.7,3,10.5,3,11.1,0,20.1-9,20.1-20.1s-1.1-7.5-3-10.5l-1.1.4c-.2,1.1-.7,2.2-1.5,3h0Z" fill="#fff" stroke-width="0"/>
<path d="M33.5,33.5c-5.4,5.4-7.1,13.6-5,23.2,1.8,7.9,6,15.9,12.1,23l2.1-2.5c-5.6-6.7-9.4-14-11.1-21.2-1.9-8.5-.5-15.7,4.1-20.2,8.8-8.8,26.6-5.5,41.5,7l2.5-2.1c-16.2-13.8-36.2-17.2-46.2-7.2Z" fill="#fff" stroke-width="0"/>
<path d="M87.3,48.2l-2.1,2.5c12.5,14.9,15.8,32.7,7,41.5-4.1,4.1-10.7,5.7-18.2,4.5-1.4.9-2.9,1.7-4.3,2.4,3.2.8,6.2,1.3,9.1,1.3,6.3,0,11.8-2,15.6-5.9,10-10.1,6.7-30.1-7.2-46.3h0Z" fill="#fff" stroke-width="0"/>
<path d="M71.2,28.5c-9.4,2.1-18.9,7.7-27,15.8-15.3,15.3-20.7,35.3-13.4,47l2.2-2.6c-5.8-10.5-.4-28.3,13.4-42.1,7.6-7.6,16.7-12.9,25.4-14.9,6.5-1.5,12.3-1,16.7,1.4l2.6-2.2c-5.2-3.3-12.2-4.2-20.1-2.4Z" fill="#fff" stroke-width="0"/>
<path d="M97,36.7l-2.2,2.6c1.8,3.3,2.5,7.5,2.1,12.3,1,1.5,1.8,3,2.6,4.5,1.6-7.6.7-14.3-2.5-19.4Z" fill="#fff" stroke-width="0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -147,58 +147,65 @@ describe('StyleManager', () => {
// go looking for cached files, and will always use the css provided
it('does not upgrade already wrapped math', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { padding: calc(10px/2); }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual("p { padding: calc(10px/2); }");
});
it('does not upgrade negative numbers', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { padding: 0 -1px; }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual("p { padding: 0 -1px; }");
});
it('upgrades simple division', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { padding: 10px/2; }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual("p { padding: calc(10px/2); }");
});
it('upgrades multi parameter math', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { padding: 0 10px/2 5em; }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual("p { padding: 0 calc(10px/2) 5em; }");
});
it('upgrades math with spaces', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { padding: 10px / 2; }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual("p { padding: calc(10px / 2); }");
});
it('upgrades multiple math expressions in a single line', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { padding: 10px/2 10px/3; }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual("p { padding: calc(10px/2) calc(10px/3); }");
});
it('does not upgrade base64 strings', () => {
// Regression Check
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { cursor: -webkit-image-set(url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAL0lEQVQoz2NgCD3x//9/BhBYBWdhgFVAiVW4JBFKGIa4AqD0//9D3pt4I4tAdAMAHTQ/j5Zom30AAAAASUVORK5CYII=')); }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual(
"p { cursor: -webkit-image-set(url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAL0lEQVQoz2NgCD3x//9/BhBYBWdhgFVAiVW4JBFKGIa4AqD0//9D3pt4I4tAdAMAHTQ/j5Zom30AAAAASUVORK5CYII=')); }"
@ -206,9 +213,10 @@ describe('StyleManager', () => {
});
it('does not modify hsl function where `/` is valid', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { caret-color: hsl(228deg 4% 24% / 0.8); }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual(
"p { caret-color: hsl(228deg 4% 24% / 0.8); }"
@ -216,9 +224,10 @@ describe('StyleManager', () => {
});
it('does not modify acos function, where math is valid', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { transform: rotate(acos(2 * 0.125)); }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual(
"p { transform: rotate(acos(2 * 0.125)); }"
@ -226,9 +235,10 @@ describe('StyleManager', () => {
});
it('recognizes valid less variables: right side', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { padding: @size + 12px; }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual(
"p { padding: calc(@size + 12px); }"
@ -236,9 +246,10 @@ describe('StyleManager', () => {
});
it('recognizes valid less variables: left side', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
let upgradedSheet = mathStyleManager.upgradeStyleSheet(
"p { padding: 12px + @size; }",
{}
{},
"math"
);
expect(upgradedSheet.source).toEqual(
"p { padding: calc(12px + @size); }"

View File

@ -27,6 +27,10 @@ module.exports = class ApplicationDelegate {
return ipcRenderer.send('open', params);
}
setWindowTheme(params) {
return ipcRenderer.send('setWindowTheme', params);
}
pickFolder(callback) {
const responseChannel = 'atom-pick-folder-response';
ipcRenderer.on(responseChannel, function(event, path) {

View File

@ -145,7 +145,8 @@ class AtomEnvironment {
config: this.config,
styleManager: this.styles,
notificationManager: this.notifications,
viewRegistry: this.views
viewRegistry: this.views,
applicationDelegate: this.applicationDelegate
});
/** @type {MenuManager} */

View File

@ -399,6 +399,11 @@ const configSchema = {
description: 'Add the current tab title to the Pulsar Window title.',
type: 'boolean',
default: true
},
syncWindowThemeWithPulsarTheme: {
description: 'When changing the theme within Pulsar also change the theme of the window on the operating system.',
type: 'boolean',
default: false
}
}
},

View File

@ -16,7 +16,8 @@ const {
dialog,
ipcMain,
shell,
screen
screen,
nativeTheme
} = require('electron');
const { CompositeDisposable, Disposable } = require('event-kit');
const crypto = require('crypto');
@ -803,6 +804,14 @@ module.exports = class AtomApplication extends EventEmitter {
})
);
this.disposable.add(
ipcHelpers.on(ipcMain, 'setWindowTheme', (event, options) => {
if (options && typeof options === 'string') {
nativeTheme.themeSource = options;
}
})
);
// A request from the associated render process to open a set of paths using the standard window location logic.
// Used for application:reopen-project.
this.disposable.add(

View File

@ -144,50 +144,54 @@ module.exports = class StyleManager {
}
}
if (params.skipDeprecatedSelectorsTransformation) {
styleElement.textContent = source;
} else {
const transformed = this.upgradeDeprecatedSelectorsForStyleSheet(
source,
params.context
let textContent = source
let deprecationMessages = [];
if (!params.skipDeprecatedSelectorsTransformation) {
const transformed = this.upgradeStyleSheet(
textContent,
params.context,
transformDeprecatedShadowDOMSelectors
);
styleElement.textContent = transformed.source;
if (transformed.deprecationMessage) {
this.deprecationsBySourcePath[params.sourcePath] = {
message: transformed.deprecationMessage
};
this.emitter.emit('did-update-deprecations');
}
textContent = transformed.source;
deprecationMessages.push(transformed.deprecationMessage);
}
if (!params.skipDeprecatedMathUsageTransformation) {
const transformed = this.upgradeDeprecatedMathUsageForStyleSheet(
styleElement.textContent,
params.context
const transformed = this.upgradeStyleSheet(
textContent,
params.context,
transformDeprecatedMathUsage
);
styleElement.textContent = transformed.source;
if (transformed.deprecationMessage) {
// Now we may already have a deprecation message from upgrading deprecated
// selectors, so we want to check if the message already exists for this
// source path, and add to it, otherwise we can create a new one
if (typeof this.deprecationsBySourcePath[params.sourcePath]?.message === "string") {
this.deprecationsBySourcePath[params.sourcePath].message += `\n${transformed.deprecationMessage}`;
this.emitter.emit('did-update-deprecations');
} else {
// lets create a new deprecation
this.deprecationsBySourcePath[params.sourcePath] = {
message: transformed.deprecationMessage
};
this.emitter.emit('did-update-deprecations');
}
}
textContent = transformed.source;
deprecationMessages.push(transformed.deprecationMessage);
}
// Once done with any and all transformations we can apply our new textContent
styleElement.textContent = textContent;
// Reduce the deprecation messages array to remove any null, undefined, or empty text values
// Anything not 'truthy'
deprecationMessages = deprecationMessages.filter((ele) => ele);
if (deprecationMessages.length > 0) {
// we do in fact have deprecations
let deprecationMsg = deprecationMessages.join("\n");
this.deprecationsBySourcePath[params.sourcePath] = {
message: deprecationMsg
};
this.emitter.emit("did-update-deprecations");
}
if (updated) {
this.emitter.emit('did-update-style-element', styleElement);
this.emitter.emit("did-update-style-element", styleElement);
} else {
this.addStyleElement(styleElement);
}
return new Disposable(() => {
this.removeStyleElement(styleElement);
});
@ -226,46 +230,36 @@ module.exports = class StyleManager {
}
}
upgradeDeprecatedSelectorsForStyleSheet(styleSheet, context) {
if (this.cacheDirPath != null) {
const hash = crypto.createHash('sha1');
if (context != null) {
hash.update(context);
}
hash.update(styleSheet);
const cacheFilePath = path.join(this.cacheDirPath, hash.digest('hex'));
try {
return JSON.parse(fs.readFileSync(cacheFilePath));
} catch (e) {
const transformed = transformDeprecatedShadowDOMSelectors(
styleSheet,
context
);
fs.writeFileSync(cacheFilePath, JSON.stringify(transformed));
return transformed;
}
} else {
return transformDeprecatedShadowDOMSelectors(styleSheet, context);
}
}
// Wrapper function useful for applying any upgrades due to deprecations
upgradeStyleSheet(styleSheet, context, upgradeName) {
let cb;
// Allows us to utilize a direct callback, or if calling from outside
// StyleManager we can define a string that works
if (upgradeName === "math") {
cb = transformDeprecatedMathUsage;
} else if (upgradeName === "selector") {
cb = transformDeprecatedShadowDOMSelectors;
} else if (typeof upgradeName === "function") {
cb = upgradeName;
}
upgradeDeprecatedMathUsageForStyleSheet(styleSheet, context) {
if (this.cacheDirPath != null) {
const hash = crypto.createHash('sha1');
const hash = crypto.createHash("sha1");
if (context != null) {
hash.update(context);
}
hash.update(styleSheet);
const cacheFilePath = path.join(this.cacheDirPath, hash.digest('hex'));
const cacheFilePath = path.join(this.cacheDirPath, hash.digest("hex"));
try {
return JSON.parse(fs.readFileSync(cacheFilePath));
} catch(e) {
const transformed = transformDeprecatedMathUsage(styleSheet, context);
const transformed = cb(styleSheet, context);
fs.writeFileSync(cacheFilePath, JSON.stringify(transformed));
return transformed;
}
} else {
return transformDeprecatedMathUsage(styleSheet, context);
return cb(styleSheet, context);
}
}

View File

@ -6,6 +6,7 @@ const { Emitter, CompositeDisposable } = require('event-kit');
const { File } = require('pathwatcher');
const fs = require('fs-plus');
const LessCompileCache = require('./less-compile-cache');
const Color = require('./color');
// Extended: Handles loading and activating available themes.
//
@ -16,8 +17,10 @@ module.exports = class ThemeManager {
config,
styleManager,
notificationManager,
viewRegistry
viewRegistry,
applicationDelegate
}) {
this.applicationDelegate = applicationDelegate;
this.packageManager = packageManager;
this.config = config;
this.styleManager = styleManager;
@ -372,6 +375,20 @@ On linux there are currently problems with watch sizes. See
return this.styleSheetDisposablesBySourcePath[path];
}
refreshWindowTheme() {
let bgColor = Color.parse(getComputedStyle(document.documentElement).backgroundColor);
let luminosity = 0.2126 * bgColor.red + 0.7152 * bgColor.green + 0.0722 * bgColor.blue;
// ^^ Luminosity per ITU-R BT.709
if (luminosity < 40) {
// Considered Dark
this.applicationDelegate.setWindowTheme("dark");
} else {
// Considered Bright
this.applicationDelegate.setWindowTheme("light");
}
}
activateThemes() {
return new Promise(resolve => {
// @config.observe runs the callback once, then on subsequent changes.
@ -396,6 +413,9 @@ On linux there are currently problems with watch sizes. See
this.refreshLessCache(); // Update cache again now that @getActiveThemes() is populated
this.loadUserStylesheet();
this.reloadBaseStylesheets();
if (this.config.get("editor.syncWindowThemeWithPulsarTheme")) {
this.refreshWindowTheme();
}
this.initialLoadComplete = true;
this.emitter.emit('did-change-active-themes');
resolve();

View File

@ -367,12 +367,10 @@ module.exports = class WASMTreeSitterGrammar {
return this.emitter.on('did-change-query-file', callback);
}
// TODO: Why is this here?
activate() {
this.registration = this.registry.addGrammar(this);
}
// TODO: Why is this here?
deactivate() {
this.registration?.dispose();
this.subscriptions?.dispose();

View File

@ -3524,6 +3524,11 @@ dedent@^0.7.0:
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==
dedent@^1.5.3:
version "1.5.3"
resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a"
integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==
deep-eql@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
@ -4883,6 +4888,11 @@ github-from-package@0.0.0:
resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==
github-markdown-css@^5.5.1:
version "5.5.1"
resolved "https://registry.yarnpkg.com/github-markdown-css/-/github-markdown-css-5.5.1.tgz#c2a609ca0b067552c8bfc09e797ace20d614f515"
integrity sha512-2osyhNgFt7DEHnGHbgIifWawAqlc68gjJiGwO1xNw/S48jivj8kVaocsVkyJqUi3fm7fdYIDi4C6yOtcqR/aEQ==
github-slugger@^1.1.1:
version "1.5.0"
resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.5.0.tgz#17891bbc73232051474d68bd867a34625c955f7d"
@ -6638,9 +6648,11 @@ markdown-it@^13.0.2:
version "0.160.2"
dependencies:
cheerio "^1.0.0-rc.3"
dedent "^1.5.3"
dompurify "^2.0.17"
emoji-images "^0.1.1"
fs-plus "^3.0.0"
github-markdown-css "^5.5.1"
marked "5.0.3"
underscore-plus "^1.0.0"
yaml-front-matter "^4.1.1"
@ -8638,9 +8650,9 @@ smart-buffer@^4.0.2, smart-buffer@^4.2.0:
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
"snippets@github:pulsar-edit/snippets#6b9163415270b8757b262f5dfaafaa05d47324a9":
version "1.7.0"
resolved "https://codeload.github.com/pulsar-edit/snippets/tar.gz/6b9163415270b8757b262f5dfaafaa05d47324a9"
"snippets@github:pulsar-edit/snippets#v1.8.0":
version "1.8.0"
resolved "https://codeload.github.com/pulsar-edit/snippets/tar.gz/31a21d2d6c7e10756f204c2fbb7bb8d140f0744d"
dependencies:
async "~0.2.6"
atom-select-list "^0.7.0"