Skip to content
Permalink
Browse files
implement matching tag support
  • Loading branch information
nightwing committed Nov 28, 2021
1 parent b0b74d7 commit 8b68884e814b0cb2dab098bde58e48d63dc73cb6
Showing with 79 additions and 39 deletions.
  1. +1 −1 package.json
  2. +54 −5 src/cm_adapter.ts
  3. +3 −4 src/index.ts
  4. +18 −19 test/vim_test.js
  5. +3 −10 test/webtest-vim.js
@@ -37,7 +37,7 @@
"@codemirror/stream-parser": "^0.19.0",
"@codemirror/basic-setup": "^0.19.0",
"@codemirror/lang-javascript": "^0.19.0",
"@codemirror/lang-html": "^0.19.0",
"@codemirror/lang-xml": "^0.19.0",
"vite": "^2.3.8"
},
"repository": {
@@ -1,5 +1,5 @@
import {
EditorSelection, Text, MapMode, ChangeDesc,
EditorSelection, Text, MapMode, ChangeDesc, EditorState,
} from "@codemirror/state"

import {StringStream} from "@codemirror/stream-parser"
@@ -12,7 +12,7 @@ import {
} from "@codemirror/commands"
import {foldCode} from "@codemirror/fold"
import * as history from "@codemirror/history"
import { indentUnit, ensureSyntaxTree } from "@codemirror/language"
import { indentUnit, ensureSyntaxTree, syntaxTree } from "@codemirror/language"

interface Pos { line: number, ch: number }
interface CM5Range { anchor: Pos, head: Pos }
@@ -183,6 +183,9 @@ export class CodeMirror {
CodeMirror.prototype[name] = fn;
};

static findMatchingTag = findMatchingTag;
static findEnclosingTag = findEnclosingTag;

// --------------------------
cm6: EditorView
state: {
@@ -379,11 +382,11 @@ export class CodeMirror {
var offset = indexFromPos(state.doc, pos);
var m = matchBrackets(state, offset + 1, -1)
if (m && m.end) {
return { to: m && posFromIndex(state.doc, m.end.from) };
return { to: posFromIndex(state.doc, m.end.from) };
}
m = matchBrackets(this.cm6.state, offset, 1)
m = matchBrackets(state, offset, 1)
if (m && m.end) {
return { to: m && posFromIndex(state.doc, m.end.from) };
return { to: posFromIndex(state.doc, m.end.from) };
}
return { to: undefined };
};
@@ -855,6 +858,52 @@ function scanForBracket(cm: CodeMirror, where: Pos, dir: -1|1, style: any, confi
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
}

function findMatchingTag(cm: CodeMirror, pos: Pos) {
var state = cm.cm6.state;
var offset = cm.indexFromPos(pos)
var doc = state.doc;
var m = matchBrackets(state, offset + 1, -1, {brackets: "\n\n"})
if (m) {
if (!m.end || !m.start) return;
return {
open: convertRange(state.doc, m.end),
close: convertRange(state.doc, m.start),
};
}
m = matchBrackets(state, offset, 1, {brackets: "\n\n"})
if (m) {
if (!m.end || !m.start) return;
return {
open: convertRange(state.doc, m.start),
close: convertRange(state.doc, m.end),
};
}
}

function convertRange(doc: Text, cm6Range: {from: number, to: number}) {
return {
from: posFromIndex(doc, cm6Range.from),
to: posFromIndex(doc, cm6Range.to)
}
}

function findEnclosingTag(cm: CodeMirror, pos: Pos) {
var state = cm.cm6.state;
var offset = cm.indexFromPos(pos)
var text = state.sliceDoc(0, offset);
var i = offset;
debugger
while (i > 0) {
var m = matchBrackets(state, i, 1, {brackets: "\n\n"})
if (m && m.start && m.end) {
return {
open: convertRange(state.doc, m.start),
close: convertRange(state.doc, m.end),
};
}
i = text.lastIndexOf(">", i - 1)
}
}


class Marker {
@@ -1,18 +1,17 @@
import {initVim} from "./vim"
import { CodeMirror } from "./cm_adapter"

const Vim = initVim(CodeMirror)

import {DrawSelectionPlugin, hideNativeSelection} from "./draw-selection"


import { Extension } from "@codemirror/state"
import { ViewPlugin, PluginValue, ViewUpdate } from "@codemirror/view"
import { EditorView } from "@codemirror/view"


import {showPanel} from "@codemirror/panel"
import {StateField, StateEffect} from "@codemirror/state"

const Vim = initVim(CodeMirror)



const vimStyle = EditorView.theme({
@@ -1318,13 +1318,12 @@ testVim('=', function(cm, vim, helpers) {
eq(expectedValue, cm.getValue());
}, { value: ' word1\n word2\n word3', indentUnit: 2 });

// Edit tests - configureCm is an optional argument that gives caller
// access to the cm object.
function testEdit(name, before, pos, edit, after, configureCm) {

// Edit tests
function testEdit(name, before, pos, edit, after, opts) {
if (!opts) opts = {};
opts.value = before;
return testVim(name, function(cm, vim, helpers) {
if (configureCm) {
configureCm(cm);
}
var ch = before.search(pos)
var line = before.substring(0, ch).split('\n').length - 1;
if (line) {
@@ -1333,7 +1332,7 @@ function testEdit(name, before, pos, edit, after, configureCm) {
cm.setCursor(line, ch);
helpers.doKeys.apply(this, edit.split(''));
eq(after, cm.getValue());
}, {value: before});
}, opts);
}

// These Delete tests effectively cover word-wise Change, Visual & Yank.
@@ -1431,24 +1430,24 @@ testEdit('da>_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'da>', 'a\tb');

// deleting tag objects
testEdit('dat_noop', '<outer><inner>hello</inner></outer>', /n/, 'dat', '<outer><inner>hello</inner></outer>');
testEdit('dat_open_tag', '<outer><inner>hello</inner></outer>', /n/, 'dat', '<outer></outer>', function(cm) {
cm.setOption('mode', 'xml');
testEdit('dat_open_tag', '<outer><inner>hello</inner></outer>', /n/, 'dat', '<outer></outer>', {
mode: 'xml'
});
testEdit('dat_inside_tag', '<outer><inner>hello</inner></outer>', /l/, 'dat', '<outer></outer>', function(cm) {
cm.setOption('mode', 'xml');
testEdit('dat_inside_tag', '<outer><inner>hello</inner></outer>', /l/, 'dat', '<outer></outer>', {
mode: 'xml'
});
testEdit('dat_close_tag', '<outer><inner>hello</inner></outer>', /\//, 'dat', '<outer></outer>', function(cm) {
cm.setOption('mode', 'xml');
testEdit('dat_close_tag', '<outer><inner>hello</inner></outer>', /\//, 'dat', '<outer></outer>', {
mode: 'xml'
});

testEdit('dit_open_tag', '<outer><inner>hello</inner></outer>', /n/, 'dit', '<outer><inner></inner></outer>', function(cm) {
cm.setOption('mode', 'xml');
testEdit('dit_open_tag', '<outer><inner>hello</inner></outer>', /n/, 'dit', '<outer><inner></inner></outer>', {
mode: 'xml'
});
testEdit('dit_inside_tag', '<outer><inner>hello</inner></outer>', /l/, 'dit', '<outer><inner></inner></outer>', function(cm) {
cm.setOption('mode', 'xml');
testEdit('dit_inside_tag', '<outer><inner>hello</inner></outer>', /l/, 'dit', '<outer><inner></inner></outer>', {
mode: 'xml'
});
testEdit('dit_close_tag', '<outer><inner>hello</inner></outer>', /\//, 'dit', '<outer><inner></inner></outer>', function(cm) {
cm.setOption('mode', 'xml');
testEdit('dit_close_tag', '<outer><inner>hello</inner></outer>', /\//, 'dit', '<outer><inner></inner></outer>', {
mode: 'xml'
});

function testSelection(name, before, pos, keys, sel) {
@@ -1,6 +1,6 @@
import {EditorState, EditorView, basicSetup} from "@codemirror/basic-setup"
import { CodeMirror, Vim, vim} from ".."
import {html} from "@codemirror/lang-html"
import { CodeMirror, Vim, vim} from "../src/index"
import {xml} from "@codemirror/lang-xml"
import {javascript} from "@codemirror/lang-javascript"
import ist from "ist";
import tests from "./vim_test.js"
@@ -13,13 +13,6 @@ import { keymap } from "@codemirror/view";
var disabled = {
"vim_ex_set_filetype": 1,
"vim_ex_set_filetype_null": 1,
"vim_dat_open_tag": 1,
"vim_dat_noop": 1,
"vim_dat_inside_tag": 1,
"vim_dat_close_tag": 1,
"vim_dit_open_tag": 1,
"vim_dit_inside_tag": 1,
"vim_dit_close_tag": 1,

"vim_ex_global_substitute_join": 1,
"vim_ex_global_substitute_split": 1,
@@ -58,7 +51,7 @@ describe("Vim extension", () => {
extensions: [
vim({}),
basicSetup,
javascript(),
options.mode == "xml" ? xml() : javascript(),
EditorState.tabSize.of(options.tabSize || 4),
indentUnit.of(options.indentWithTabs ? "\t" : " ".repeat(options.indentUnit || 2)),
// keymap.of([indentWithTab]),

0 comments on commit 8b68884

Please sign in to comment.