Permalink
Browse files

Less naive text object implementation.

We need to deal with matched pairs of delimieters, not the next and previous
delimeters that we find.
  • Loading branch information...
1 parent 48593a5 commit e9b52daf3f3191aff9200337fed67bf3a31a4d40 @georgebrock georgebrock committed Dec 17, 2012
Showing with 78 additions and 30 deletions.
  1. +45 −30 js/text_objects.js
  2. +33 −0 tests/unit/text_object.js
View
@@ -1,48 +1,63 @@
(function () {
+ function findPairs(lines, start, end) {
+ var row, col, line, chr, pairs, startStack;
+
+ pairs = [];
+ startStack = [];
+
+ for (row = 0; row < lines.length; row++) {
+ line = lines[row];
+ for (col = 0; col < line.length; col++) {
+ chr = line.charAt(col);
+ if (chr === start) {
+ startStack.push({row: row, col: col});
+ } else if (chr === end && startStack.length > 0) {
+ pairs.push(new Vimulator.CharacterRange(
+ startStack.pop(),
+ {row: row, col: col},
+ {inclusive: true}
+ ));
+ }
+ }
+ }
+
+ return pairs;
+ }
+
Vimulator.TextObject = function (options) {
this.startDelim = options.start;
this.endDelim = options.end;
this.name = options.name;
};
Vimulator.TextObject.prototype.insideRange = function (vim) {
- var start, end;
-
- start = vim.findLast(this.startDelim, {
- offset: 1,
- wrap: true,
- inclusive: true
- });
- end = vim.findNext(this.endDelim, {
- offset: -1,
- wrap: true,
- inclusive: true
- });
+ var pairs, i, p;
- if (start && end) {
- return new Vimulator.CharacterRange(start, end, {inclusive: true});
- } else {
- return null;
+ pairs = findPairs(vim.lines, this.startDelim, this.endDelim);
+ for (i = 0; i < pairs.length; i++) {
+ p = pairs[i];
+ if (p.contains(vim.cursor)) {
+ p.start.col += 1;
+ p.end.col -= 1;
+ return p;
+ }
}
+
+ return null;
};
Vimulator.TextObject.prototype.aroundRange = function (vim) {
- var start, end;
+ var pairs, i, p;
- start = vim.findLast(this.startDelim, {
- wrap: true,
- inclusive: true
- });
- end = vim.findNext(this.endDelim, {
- wrap: true,
- inclusive: true
- });
-
- if (start && end) {
- return new Vimulator.CharacterRange(start, end, {inclusive: true});
- } else {
- return null;
+ pairs = findPairs(vim.lines, this.startDelim, this.endDelim);
+ for (i = 0; i < pairs.length; i++) {
+ p = pairs[i];
+ if (p.contains(vim.cursor)) {
+ return p;
+ }
}
+
+ return null;
};
Vimulator.TextObject.Commands = (function () {
View
@@ -39,6 +39,28 @@ describe("TextObject", function () {
expect(range).toBe(null);
});
+
+ it("handles outer nested parens", function () {
+ var range;
+ vim.lines = ["(Outer (inner) outer)"];
+ vim.cursor.col = 17;
+ range = to.insideRange(vim);
+
+ expect(range.start).toEqual({row: 0, col: 1});
+ expect(range.end).toEqual({row: 0, col: 19});
+ expect(range.inclusive).toBe(true);
+ });
+
+ it("handles inner nested parens", function () {
+ var range;
+ vim.lines = ["(Outer (inner) outer)"];
+ vim.cursor.col = 10;
+ range = to.insideRange(vim);
+
+ expect(range.start).toEqual({row: 0, col: 8});
+ expect(range.end).toEqual({row: 0, col: 12});
+ expect(range.inclusive).toBe(true);
+ });
});
describe(".aroundRange", function () {
@@ -74,5 +96,16 @@ describe("TextObject", function () {
expect(range).toBe(null);
});
+
+ it("handles nested parens", function () {
+ var range;
+ vim.lines = ["(Outer (inner) outer)"];
+ vim.cursor.col = 17;
+ range = to.aroundRange(vim);
+
+ expect(range.start).toEqual({row: 0, col: 0});
+ expect(range.end).toEqual({row: 0, col: 20});
+ expect(range.inclusive).toBe(true);
+ });
});
});

0 comments on commit e9b52da

Please sign in to comment.