From c4c41880dceb775d1f8971ec86d772545dd420f7 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 12 Jul 2024 08:50:26 +0200 Subject: [PATCH 1/3] Migrating markdown scopes --- data/fixtures/scopes/markdown/section.scope | 66 ++++++++++++++++ .../scopeSupportFacetInfos.ts | 5 ++ .../scopeSupportFacets.types.ts | 3 +- .../src/languages/LegacyLanguageId.ts | 1 - .../queryPredicateOperators.ts | 10 ++- .../src/languages/branchMatcher.ts | 33 -------- .../src/languages/getNodeMatcher.ts | 2 - .../src/languages/markdown.ts | 76 ------------------- .../src/languages/ternaryBranchMatcher.ts | 40 ---------- queries/markdown.scm | 58 ++++++++++++++ 10 files changed, 137 insertions(+), 157 deletions(-) create mode 100644 data/fixtures/scopes/markdown/section.scope delete mode 100644 packages/cursorless-engine/src/languages/branchMatcher.ts delete mode 100644 packages/cursorless-engine/src/languages/markdown.ts delete mode 100644 packages/cursorless-engine/src/languages/ternaryBranchMatcher.ts diff --git a/data/fixtures/scopes/markdown/section.scope b/data/fixtures/scopes/markdown/section.scope new file mode 100644 index 0000000000..c9f829b667 --- /dev/null +++ b/data/fixtures/scopes/markdown/section.scope @@ -0,0 +1,66 @@ +# H1 + +Sub 1 + +## H2 + +Sub 2 + +# H1.2 +--- + +[#1 Content] = +[#1 Domain] = 0:0-6:5 + >---- +0| # H1 +1| +2| Sub 1 +3| +4| ## H2 +5| +6| Sub 2 + -----< + +[#1 Removal] = 0:0-8:0 + >---- +0| # H1 +1| +2| Sub 1 +3| +4| ## H2 +5| +6| Sub 2 +7| +8| # H1.2 + < + +[#1 Insertion delimiter] = "\n\n" + + +[#2 Content] = +[#2 Domain] = 4:0-6:5 + >----- +4| ## H2 +5| +6| Sub 2 + -----< + +[#2 Removal] = 4:0-8:0 + >----- +4| ## H2 +5| +6| Sub 2 +7| +8| # H1.2 + < + +[#2 Insertion delimiter] = "\n\n" + + +[#3 Content] = +[#3 Removal] = +[#3 Domain] = 8:0-8:6 + >------< +8| # H1.2 + +[#3 Insertion delimiter] = "\n\n" diff --git a/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts b/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts index f0ab4eab8e..8a7c16c5e6 100644 --- a/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts +++ b/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts @@ -38,6 +38,11 @@ export const scopeSupportFacetInfos: Record< scopeType: "environment", }, + section: { + description: "A document section/chapter/subsection/etc", + scopeType: "section", + }, + list: { description: "A list/array", scopeType: "list", diff --git a/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts b/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts index 22276f1eff..e6ba9d569b 100644 --- a/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts +++ b/packages/common/src/scopeSupportFacets/scopeSupportFacets.types.ts @@ -11,6 +11,8 @@ const scopeSupportFacets = [ "environment", + "section", + "list", "map", "ifStatement", @@ -162,7 +164,6 @@ const scopeSupportFacets = [ "notebookCell", // FIXME: Still in legacy - // section // selector // unit // collectionItem diff --git a/packages/cursorless-engine/src/languages/LegacyLanguageId.ts b/packages/cursorless-engine/src/languages/LegacyLanguageId.ts index 1703d0acb8..618ca33864 100644 --- a/packages/cursorless-engine/src/languages/LegacyLanguageId.ts +++ b/packages/cursorless-engine/src/languages/LegacyLanguageId.ts @@ -7,7 +7,6 @@ export const legacyLanguageIds = [ "csharp", "css", "latex", - "markdown", "php", "ruby", "rust", diff --git a/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts b/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts index c00cd5738b..8814a46c86 100644 --- a/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts +++ b/packages/cursorless-engine/src/languages/TreeSitterQuery/queryPredicateOperators.ts @@ -168,10 +168,12 @@ class TrimEnd extends QueryPredicateOperator { const { document, range } = nodeInfo; const text = document.getText(range); const whitespaceLength = text.length - text.trimEnd().length; - nodeInfo.range = new Range( - range.start, - adjustPosition(document, range.end, -whitespaceLength), - ); + if (whitespaceLength > 0) { + nodeInfo.range = new Range( + range.start, + adjustPosition(document, range.end, -whitespaceLength), + ); + } return true; } } diff --git a/packages/cursorless-engine/src/languages/branchMatcher.ts b/packages/cursorless-engine/src/languages/branchMatcher.ts deleted file mode 100644 index 63b93d874f..0000000000 --- a/packages/cursorless-engine/src/languages/branchMatcher.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { NodeMatcher } from "../typings/Types"; -import { patternFinder } from "../util/nodeFinders"; -import { - cascadingMatcher, - matcher, - patternMatcher, -} from "../util/nodeMatchers"; -import { childRangeSelector } from "../util/nodeSelectors"; - -/** - * Constructs a branch matcher for constructs that have a primary branch - * followed by zero or more optional branches, such as `if` statements or `try` - * statements - * @param statementType The top-level statement type for this construct, eg - * "if_statement" or "try_statement" - * @param optionalBranchTypes The optional branch type names that can be - * children of the top-level statement, eg "else_clause" or "except_clause" - * @returns A node matcher capable of matching this type of branch - */ -export function branchMatcher( - statementType: string, - optionalBranchTypes: string[], -): NodeMatcher { - return cascadingMatcher( - patternMatcher(...optionalBranchTypes), - matcher( - patternFinder(statementType), - childRangeSelector(optionalBranchTypes, [], { - includeUnnamedChildren: true, - }), - ), - ); -} diff --git a/packages/cursorless-engine/src/languages/getNodeMatcher.ts b/packages/cursorless-engine/src/languages/getNodeMatcher.ts index bc4edc1768..d153631ecf 100644 --- a/packages/cursorless-engine/src/languages/getNodeMatcher.ts +++ b/packages/cursorless-engine/src/languages/getNodeMatcher.ts @@ -12,7 +12,6 @@ import clojure from "./clojure"; import { LegacyLanguageId } from "./LegacyLanguageId"; import csharp from "./csharp"; import latex from "./latex"; -import markdown from "./markdown"; import php from "./php"; import { patternMatchers as ruby } from "./ruby"; import rust from "./rust"; @@ -51,7 +50,6 @@ export const languageMatchers: Record< csharp, css: scss, latex, - markdown, php, ruby, rust, diff --git a/packages/cursorless-engine/src/languages/markdown.ts b/packages/cursorless-engine/src/languages/markdown.ts deleted file mode 100644 index 9ccd16ddc1..0000000000 --- a/packages/cursorless-engine/src/languages/markdown.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { SimpleScopeTypeType, TextEditor } from "@cursorless/common"; -import type { SyntaxNode } from "web-tree-sitter"; -import { NodeFinder, NodeMatcherAlternative } from "../typings/Types"; -import { leadingSiblingNodeFinder, patternFinder } from "../util/nodeFinders"; -import { createPatternMatchers, matcher } from "../util/nodeMatchers"; -import { extendUntilNextMatchingSiblingOrLast } from "../util/nodeSelectors"; -import { shrinkRangeToFitContent } from "../util/selectionUtils"; - -const HEADING_MARKER_TYPES = [ - "atx_h1_marker", - "atx_h2_marker", - "atx_h3_marker", - "atx_h4_marker", - "atx_h5_marker", - "atx_h6_marker", -] as const; -type HeadingMarkerType = (typeof HEADING_MARKER_TYPES)[number]; - -/** - * Returns a node finder that will only accept nodes of heading level at least - * as high as the given heading level type - * @param headingType The heading type of the node we'll be starting at - * @returns A node finder that will return the next node that is of the same - * marker level or higher than the original type - */ -function makeMinimumHeadingLevelFinder( - headingType: HeadingMarkerType, -): NodeFinder { - const markerIndex = HEADING_MARKER_TYPES.indexOf(headingType); - return (node: SyntaxNode) => { - return node.type === "atx_heading" && - HEADING_MARKER_TYPES.indexOf( - node.firstNamedChild?.type as HeadingMarkerType, - ) <= markerIndex - ? node - : null; - }; -} - -function sectionExtractor(editor: TextEditor, node: SyntaxNode) { - const finder = makeMinimumHeadingLevelFinder( - node.firstNamedChild?.type as HeadingMarkerType, - ); - - const { context, selection } = extendUntilNextMatchingSiblingOrLast( - editor, - node, - finder, - ); - return { - context, - selection: shrinkRangeToFitContent(editor, selection).toSelection( - selection.isReversed, - ), - }; -} - -function sectionMatcher(...patterns: string[]) { - const finder = patternFinder(...patterns); - - return matcher(leadingSiblingNodeFinder(finder), sectionExtractor); -} - -const nodeMatchers: Partial< - Record -> = { - section: sectionMatcher("atx_heading"), - sectionLevelOne: sectionMatcher("atx_heading.atx_h1_marker"), - sectionLevelTwo: sectionMatcher("atx_heading.atx_h2_marker"), - sectionLevelThree: sectionMatcher("atx_heading.atx_h3_marker"), - sectionLevelFour: sectionMatcher("atx_heading.atx_h4_marker"), - sectionLevelFive: sectionMatcher("atx_heading.atx_h5_marker"), - sectionLevelSix: sectionMatcher("atx_heading.atx_h6_marker"), -}; - -export default createPatternMatchers(nodeMatchers); diff --git a/packages/cursorless-engine/src/languages/ternaryBranchMatcher.ts b/packages/cursorless-engine/src/languages/ternaryBranchMatcher.ts deleted file mode 100644 index a89ccf8d94..0000000000 --- a/packages/cursorless-engine/src/languages/ternaryBranchMatcher.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { SyntaxNode } from "web-tree-sitter"; -import { NodeMatcher } from "../typings/Types"; -import { matcher } from "../util/nodeMatchers"; - -/** - * Constructs a matcher for matching ternary branches. Branches are expected to - * be named children at particular indices of a ternary node. - * - * NB: We can't just use the "foo[0]" syntax of our pattern language because - * that just uses `foo` for the finder; the `[0]` is just part of the extractor, - * so if we had `foo[0]` and `foo[1]`, they would both match for either branch. - * @param ternaryTypename The type name for ternary expressions - * @param acceptableNamedChildIndices Which named children, by index, of the - * ternary node correspond to branches - * @returns A matcher that can match ternary branches - */ -export function ternaryBranchMatcher( - ternaryTypename: string, - acceptableNamedChildIndices: number[], -): NodeMatcher { - function finder(node: SyntaxNode) { - const parent = node.parent; - if (parent == null) { - return null; - } - - if ( - parent.type === ternaryTypename && - acceptableNamedChildIndices.some((index) => - parent.namedChild(index)!.equals(node), - ) - ) { - return node; - } - - return null; - } - - return matcher(finder); -} diff --git a/queries/markdown.scm b/queries/markdown.scm index 537bfc2ecf..3015d3facd 100644 --- a/queries/markdown.scm +++ b/queries/markdown.scm @@ -75,3 +75,61 @@ (#trim-end! @notebookCell) (#insertion-delimiter! @notebookCell "\n\n") ) + +;;!! # H1 +;;!! ## H2 +( + (section) @section @_.removal + (#trim-end! @section) +) + +;;!! # H1 +( + (section + (atx_heading + (atx_h1_marker) + ) + ) @sectionLevelOne @_.removal + (#trim-end! @sectionLevelOne) +) +;;!! ## H2 +( + (section + (atx_heading + (atx_h2_marker) + ) + ) @sectionLevelTwo @_.removal + (#trim-end! @sectionLevelTwo) +) +( + (section + (atx_heading + (atx_h3_marker) + ) + ) @sectionLevelThree @_.removal + (#trim-end! @sectionLevelThree) +) +( + (section + (atx_heading + (atx_h4_marker) + ) + ) @sectionLevelFour @_.removal + (#trim-end! @sectionLevelFour) +) +( + (section + (atx_heading + (atx_h5_marker) + ) + ) @sectionLevelFive @_.removal + (#trim-end! @sectionLevelFive) +) +( + (section + (atx_heading + (atx_h6_marker) + ) + ) @sectionLevelSix @_.removal + (#trim-end! @sectionLevelSix) +) From 8cd7b070259d0f290f3da373ae45a5f021b41ff2 Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Fri, 12 Jul 2024 08:58:24 +0200 Subject: [PATCH 2/3] Added scope support --- packages/common/src/scopeSupportFacets/markdown.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/common/src/scopeSupportFacets/markdown.ts b/packages/common/src/scopeSupportFacets/markdown.ts index accdd66c93..c75edb1d60 100644 --- a/packages/common/src/scopeSupportFacets/markdown.ts +++ b/packages/common/src/scopeSupportFacets/markdown.ts @@ -9,5 +9,6 @@ const { supported, unsupported, notApplicable } = ScopeSupportFacetLevel; export const markdownScopeSupport: LanguageScopeSupportFacetMap = { "comment.line": supported, "comment.block": supported, + section: supported, notebookCell: supported, }; From facfe6b9afc773fd1d40ea48861c8e45bea7239b Mon Sep 17 00:00:00 2001 From: Andreas Arvidsson Date: Sun, 28 Jul 2024 17:54:31 +0200 Subject: [PATCH 3/3] Update description --- .../common/src/scopeSupportFacets/scopeSupportFacetInfos.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts b/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts index 8a7c16c5e6..2212c5785b 100644 --- a/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts +++ b/packages/common/src/scopeSupportFacets/scopeSupportFacetInfos.ts @@ -39,7 +39,7 @@ export const scopeSupportFacetInfos: Record< }, section: { - description: "A document section/chapter/subsection/etc", + description: "A document section", scopeType: "section", },