Skip to content

Commit f919f22

Browse files
committed
Respect don't count comments setting
1 parent 8d6f6e8 commit f919f22

File tree

2 files changed

+70
-14
lines changed

2 files changed

+70
-14
lines changed

src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ export const MATCH_HTML_COMMENT = new RegExp(
99
"|<[?][^>]*>?",
1010
"g"
1111
);
12-
export const MATCH_COMMENT = new RegExp("%%[^%%]+%%", "g");
12+
export const MATCH_COMMENT = new RegExp("%%[\\s\\S]*?(?!%%)[\\s\\S]+?%%", "g");
1313
export const MATCH_PARAGRAPH = new RegExp("\n([^\n]+)\n", "g");

src/editor/EditorPlugin.ts

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Line, RangeSetBuilder, StateEffect, StateField, Text, Transaction } from "@codemirror/state";
1+
import { EditorState, Line, RangeSetBuilder, StateEffect, StateField, Transaction } from "@codemirror/state";
22
import {
33
ViewUpdate,
44
PluginValue,
@@ -8,8 +8,10 @@ import {
88
Decoration,
99
WidgetType,
1010
} from "@codemirror/view";
11+
import { syntaxTree } from "@codemirror/language";
1112
import type BetterWordCount from "src/main";
1213
import { getWordCount } from "src/utils/StatUtils";
14+
import { MATCH_COMMENT, MATCH_HTML_COMMENT } from "src/constants";
1315

1416
export const pluginField = StateField.define<BetterWordCount>({
1517
create() {
@@ -111,6 +113,7 @@ class SectionWidget extends WidgetType {
111113
}
112114
}
113115

116+
const mdCommentRe = /%%/g;
114117
class SectionWordCountEditorPlugin implements PluginValue {
115118
decorations: DecorationSet;
116119
lineCounts: any[] = [];
@@ -122,20 +125,40 @@ class SectionWordCountEditorPlugin implements PluginValue {
122125
return;
123126
}
124127

125-
this.calculateLineCounts(view.state.doc);
128+
this.calculateLineCounts(view.state, plugin);
126129
this.decorations = this.mkDeco(view);
127130
}
128131

129-
calculateLineCounts(doc: Text) {
130-
for (let index = 0; index < doc.lines; index++) {
131-
const line = doc.line(index + 1);
132-
this.lineCounts.push(getWordCount(line.text));
132+
calculateLineCounts(state: EditorState, plugin: BetterWordCount) {
133+
const stripComments = plugin.settings.countComments;
134+
let docStr = state.doc.toString();
135+
136+
if (stripComments) {
137+
// Strip out comments, but preserve new lines for accurate positioning data
138+
const preserveNl = (match: string, offset: number, str: string) => {
139+
let output = '';
140+
for (let i = offset, len = offset + match.length; i < len; i++) {
141+
if (/[\r\n]/.test(str[i])) {
142+
output += str[i];
143+
}
144+
}
145+
return output;
146+
}
147+
148+
docStr = docStr.replace(MATCH_COMMENT, preserveNl).replace(MATCH_HTML_COMMENT, preserveNl);
149+
}
150+
151+
const lines = docStr.split(state.facet(EditorState.lineSeparator) || /\r\n?|\n/)
152+
153+
for (let i = 0, len = lines.length; i < len; i++) {
154+
let line = lines[i];
155+
this.lineCounts.push(getWordCount(line));
133156
}
134157
}
135158

136159
update(update: ViewUpdate) {
137160
const plugin = update.view.state.field(pluginField);
138-
const { displaySectionCounts } = plugin.settings;
161+
const { displaySectionCounts, countComments: stripComments } = plugin.settings;
139162
let didSettingsChange = false;
140163

141164
if (this.lineCounts.length && !displaySectionCounts) {
@@ -144,37 +167,70 @@ class SectionWordCountEditorPlugin implements PluginValue {
144167
return;
145168
} else if (!this.lineCounts.length && displaySectionCounts) {
146169
didSettingsChange = true;
147-
this.calculateLineCounts(update.startState.doc);
170+
this.calculateLineCounts(update.startState, plugin);
148171
}
149172

150173
if (update.docChanged) {
151174
const startDoc = update.startState.doc;
175+
152176
let tempDoc = startDoc;
177+
let editStartLine = Infinity;
178+
let editEndLine = -Infinity;
153179

154180
update.changes.iterChanges((fromA, toA, fromB, toB, text) => {
155181
const from = fromB;
156182
const to = fromB + (toA - fromA);
157183
const nextTo = from + text.length;
158-
184+
159185
const fromLine = tempDoc.lineAt(from);
160186
const toLine = tempDoc.lineAt(to);
161187

162188
tempDoc = tempDoc.replace(fromB, fromB + (toA - fromA), text);
163189

164-
const fromLineNext = tempDoc.lineAt(from);
165-
const toLineNext = tempDoc.lineAt(nextTo);
166-
190+
const nextFromLine = tempDoc.lineAt(from);
191+
const nextToLine = tempDoc.lineAt(nextTo);
167192
const lines: any[] = [];
168193

169-
for (let i = fromLineNext.number; i <= toLineNext.number; i++) {
194+
for (let i = nextFromLine.number; i <= nextToLine.number; i++) {
170195
lines.push(getWordCount(tempDoc.line(i).text));
171196
}
172197

173198
const spliceStart = fromLine.number - 1;
174199
const spliceLen = toLine.number - fromLine.number + 1;
175200

201+
editStartLine = Math.min(editStartLine, spliceStart);
202+
editEndLine = Math.max(editEndLine, spliceStart + (nextToLine.number - nextFromLine.number + 1));
203+
176204
this.lineCounts.splice(spliceStart, spliceLen, ...lines);
177205
});
206+
207+
// Filter out any counts associated with comments in the lines that were edited
208+
if (stripComments) {
209+
const tree = syntaxTree(update.state);
210+
for (let i = editStartLine; i < editEndLine; i++) {
211+
const line = update.state.doc.line(i + 1);
212+
let newLine = '';
213+
let pos = 0;
214+
let foundComment = false;
215+
216+
tree.iterate({
217+
enter(node) {
218+
if (node.name && /comment/.test(node.name)) {
219+
foundComment = true;
220+
newLine += line.text.substring(pos, node.from - line.from);
221+
pos = node.to - line.from;
222+
}
223+
},
224+
from: line.from,
225+
to: line.to,
226+
});
227+
228+
if (foundComment) {
229+
newLine += line.text.substring(pos);
230+
this.lineCounts[i] = getWordCount(newLine);
231+
}
232+
}
233+
}
178234
}
179235

180236
if (update.docChanged || update.viewportChanged || didSettingsChange) {

0 commit comments

Comments
 (0)