Skip to content

Commit 50f8c19

Browse files
committedFeb 2, 2025
[WIP] Add lineComments CodeMirror extension - lineCommentsExpandedPlugin
1 parent a1bf1c5 commit 50f8c19

3 files changed

+89
-26
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Decoration, EditorView, ViewPlugin, ViewUpdate, type DecorationSet } from '@codemirror/view';
2+
import { RangeSetBuilder, StateEffect } from '@codemirror/state';
3+
import { expandedLineNumbersCompartment, expandedLineNumbersFacet } from 'codecrafters-frontend/utils/code-mirror-line-comments';
4+
5+
const lineCommentsExpandedDecoration = Decoration.line({
6+
attributes: { class: 'cm-lineCommentsExpanded' },
7+
});
8+
9+
function lineCommentsExpandedDecorations(view: EditorView) {
10+
const expandedLines = view.state.facet(expandedLineNumbersFacet)[0] || [];
11+
const builder = new RangeSetBuilder<Decoration>();
12+
13+
for (const { from, to } of view.visibleRanges) {
14+
for (let pos = from; pos <= to; ) {
15+
const line = view.state.doc.lineAt(pos);
16+
17+
if (expandedLines.includes(line.number)) {
18+
builder.add(line.from, line.from, lineCommentsExpandedDecoration);
19+
}
20+
21+
pos = line.to + 1;
22+
}
23+
}
24+
25+
return builder.finish();
26+
}
27+
28+
export function lineCommentsExpandedPlugin() {
29+
return ViewPlugin.fromClass(
30+
class {
31+
decorations: DecorationSet;
32+
33+
constructor(view: EditorView) {
34+
this.decorations = lineCommentsExpandedDecorations(view);
35+
}
36+
37+
update(update: ViewUpdate) {
38+
if (update.transactions) {
39+
for (const tr of update.transactions) {
40+
for (const effect of tr.effects) {
41+
if (effect instanceof StateEffect && effect.value?.compartment === expandedLineNumbersCompartment) {
42+
this.decorations = lineCommentsExpandedDecorations(update.view);
43+
break;
44+
}
45+
}
46+
}
47+
}
48+
}
49+
},
50+
{
51+
decorations: (v) => v.decorations,
52+
},
53+
);
54+
}

‎app/utils/code-mirror-line-comments-widget.ts

+23-21
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
import { Decoration, EditorView, WidgetType, type DecorationSet } from '@codemirror/view';
2-
import { Line, StateEffect, StateField } from '@codemirror/state';
3-
import { lineDataFacet, expandedLineNumbersFacet, expandedLineNumbersCompartment } from 'codecrafters-frontend/utils/code-mirror-line-comments';
2+
import { Line, /* StateEffect, */ StateField } from '@codemirror/state';
3+
import { lineDataFacet /*, expandedLineNumbersFacet, expandedLineNumbersCompartment */ } from 'codecrafters-frontend/utils/code-mirror-line-comments';
44

55
class LineCommentsWidget extends WidgetType {
66
line: Line;
7-
isExpanded: boolean;
7+
// isExpanded: boolean;
88

9-
constructor(line: Line, isExpanded: boolean = false) {
9+
constructor(line: Line /* , isExpanded: boolean = false */) {
1010
super();
1111
this.line = line;
12-
this.isExpanded = isExpanded;
12+
// this.isExpanded = isExpanded;
1313
}
1414

1515
toDOM(view: EditorView): HTMLElement {
16-
const expandedLines = view.state.facet(expandedLineNumbersFacet)[0] || [];
16+
// const expandedLines = view.state.facet(expandedLineNumbersFacet)[0] || [];
1717
const commentsCount = view.state.facet(lineDataFacet)[0]?.dataForLine(this.line.number)?.commentsCount || 0;
1818
const classNames = ['cm-lineCommentsWidget'];
1919

20-
if (expandedLines.includes(this.line.number) || this.isExpanded) {
21-
classNames.push('cm-lineCommentsWidgetExpanded');
22-
}
20+
// if (expandedLines.includes(this.line.number) || this.isExpanded) {
21+
// classNames.push('cm-lineCommentsWidgetExpanded');
22+
// }
2323

2424
const elem = document.createElement('div');
2525
elem.className = classNames.join(' ');
@@ -55,15 +55,15 @@ const lineCommentsWidgetStateField = StateField.define<DecorationSet>({
5555

5656
// let newDecorations = decorations.map(transaction.changes);
5757

58-
for (const effect of transaction.effects) {
59-
if (effect instanceof StateEffect && effect.value?.compartment === expandedLineNumbersCompartment) {
60-
return this.create(transaction.state);
58+
// for (const effect of transaction.effects) {
59+
// if (effect instanceof StateEffect && effect.value?.compartment === expandedLineNumbersCompartment) {
60+
// // return this.create(transaction.state);
6161

62-
// newDecorations = newDecorations.update({ filter: (pos) => pos !== effect.value.pos }).update({
63-
// add: [lineCommentsWidgetDecoration(transaction.state.doc.lineAt(effect.value.pos))],
64-
// });
65-
}
66-
}
62+
// newDecorations = newDecorations.update({ filter: (pos) => pos !== effect.value.pos }).update({
63+
// add: [lineCommentsWidgetDecoration(transaction.state.doc.lineAt(effect.value.pos))],
64+
// });
65+
// }
66+
// }
6767

6868
// return newDecorations;
6969

@@ -82,15 +82,17 @@ const lineCommentsWidgetBaseTheme = EditorView.baseTheme({
8282
backgroundColor: '#009bff40',
8383
paddingLeft: '1rem',
8484
marginRight: '-1rem',
85+
},
8586

86-
'&.cm-lineCommentsWidgetExpanded': {
87+
'&.cm-lineCommentsExpanded': {
88+
'& .cm-lineCommentsWidget': {
8789
display: 'block',
8890
backgroundColor: '#009bff80',
8991
},
92+
},
9093

91-
'& + br': {
92-
display: 'none',
93-
},
94+
'& .cm-lineCommentsWidget + br': {
95+
display: 'none',
9496
},
9597

9698
'& .cm-insertedLine + br': {

‎app/utils/code-mirror-line-comments.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { Compartment, Facet, StateEffect } from '@codemirror/state';
1+
import { Compartment, Facet } from '@codemirror/state';
22
import { lineCommentsWidget } from 'codecrafters-frontend/utils/code-mirror-line-comments-widget';
33
import { lineCommentsGutter } from 'codecrafters-frontend/utils/code-mirror-line-comments-gutter';
4+
import { lineCommentsExpandedPlugin } from 'codecrafters-frontend/utils/code-mirror-line-comments-expanded-plugin';
45

56
export class LineData {
67
commentsCount: number;
@@ -30,10 +31,16 @@ export const expandedLineNumbersFacet = Facet.define<number[]>();
3031

3132
export const expandedLineNumbersCompartment = new Compartment();
3233

33-
export const toggleLineCommentsEffect = StateEffect.define<{ pos: number; isExpanded: boolean }>({
34-
map: (value, mapping) => ({ pos: mapping.mapPos(value.pos), isExpanded: value.isExpanded }),
35-
});
34+
// export const toggleLineCommentsEffect = StateEffect.define<{ pos: number; isExpanded: boolean }>({
35+
// map: (value, mapping) => ({ pos: mapping.mapPos(value.pos), isExpanded: value.isExpanded }),
36+
// });
3637

3738
export function lineComments(lineData: LineDataCollection) {
38-
return [lineDataFacet.of(lineData), expandedLineNumbersCompartment.of(expandedLineNumbersFacet.of([])), lineCommentsWidget(), lineCommentsGutter()];
39+
return [
40+
lineDataFacet.of(lineData),
41+
expandedLineNumbersCompartment.of(expandedLineNumbersFacet.of([])),
42+
lineCommentsWidget(),
43+
lineCommentsGutter(),
44+
lineCommentsExpandedPlugin(),
45+
];
3946
}

0 commit comments

Comments
 (0)
Failed to load comments.