Skip to content

Commit 2268d72

Browse files
committed
fix: indent logic that doing in invalid cases
1 parent 1082410 commit 2268d72

File tree

4 files changed

+77
-39
lines changed

4 files changed

+77
-39
lines changed

CHANGELOG.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1-
2-
31
## [0.16.5](https://github.com/arshad-yaseen/monacopilot/compare/v0.16.4...v0.16.5) (2024-12-28)
42

5-
63
### 🔧 Maintenance
74

8-
* indent new lines of completion based on current column ([4c9fe26](https://github.com/arshad-yaseen/monacopilot/commit/4c9fe26d2e20795ec2adc3860ad305f405f64a65))
9-
5+
- indent new lines of completion based on current column ([4c9fe26](https://github.com/arshad-yaseen/monacopilot/commit/4c9fe26d2e20795ec2adc3860ad305f405f64a65))
106

117
### 💥 Breaking Changes
128

13-
* drop deprecated registerCopilot ([e2ce7a2](https://github.com/arshad-yaseen/monacopilot/commit/e2ce7a2d1eb61b58818ca62a7d7b5f3388e08220))
9+
- drop deprecated registerCopilot ([e2ce7a2](https://github.com/arshad-yaseen/monacopilot/commit/e2ce7a2d1eb61b58818ca62a7d7b5f3388e08220))
1410

1511
## [0.16.4](https://github.com/arshad-yaseen/monacopilot/compare/v0.16.3...v0.16.4) (2024-12-25)
1612

src/classes/completion-formatter.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@
55
export class CompletionFormatter {
66
private formattedCompletion = '';
77
private currentColumn = 0;
8+
private textBeforeCursorInLine = '';
89

9-
private constructor(completion: string, currentColumn: number) {
10-
this.formattedCompletion = completion;
11-
this.currentColumn = currentColumn;
12-
}
13-
14-
public static create(
10+
constructor(
1511
completion: string,
1612
currentColumn: number,
17-
): CompletionFormatter {
18-
return new CompletionFormatter(completion, currentColumn);
13+
textBeforeCursorInLine: string,
14+
) {
15+
this.formattedCompletion = completion;
16+
this.currentColumn = currentColumn;
17+
this.textBeforeCursorInLine = textBeforeCursorInLine;
1918
}
2019

2120
public setCompletion(completion: string): CompletionFormatter {
@@ -36,10 +35,18 @@ export class CompletionFormatter {
3635
}
3736

3837
public indentByColumn(): CompletionFormatter {
38+
// Split completion into lines
3939
const lines = this.formattedCompletion.split('\n');
40-
if (lines.length <= 1) return this;
4140

41+
// Skip indentation if there's only one line or if there's text before cursor in the line
42+
if (lines.length <= 1 || this.textBeforeCursorInLine.trim() !== '') {
43+
return this;
44+
}
45+
46+
// Create indentation string based on current column position
4247
const indentation = ' '.repeat(this.currentColumn - 1);
48+
49+
// Keep first line as is, indent all subsequent lines
4350
this.formattedCompletion =
4451
lines[0] +
4552
'\n' +

src/core/completion/handler.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import {
1010
InlineCompletionHandlerParams,
1111
TriggerType,
1212
} from '../../types';
13-
import {getTextBeforeCursor, typingDebouncedAsync} from '../../utils';
13+
import {
14+
getTextBeforeCursor,
15+
getTextBeforeCursorInLine,
16+
typingDebouncedAsync,
17+
} from '../../utils';
1418
import {createInlineCompletionResult} from '../../utils/completion';
1519

1620
/**
@@ -99,9 +103,10 @@ const handleInlineCompletions = async ({
99103
});
100104

101105
if (completion) {
102-
const formattedCompletion = CompletionFormatter.create(
106+
const formattedCompletion = new CompletionFormatter(
103107
completion,
104108
pos.column,
109+
getTextBeforeCursorInLine(pos, mdl),
105110
)
106111
.removeMarkdownCodeSyntax()
107112
.removeExcessiveNewlines()

tests/completion-formatter.test.ts

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,41 @@ import {MOCK_COMPLETION_POS} from './mock';
66
describe('CompletionFormatter', () => {
77
describe('create', () => {
88
it('should create a new instance of CompletionFormatter', () => {
9-
const formatter = CompletionFormatter.create(
9+
const formatter = new CompletionFormatter(
1010
'const greeting = "Hello, World!";',
1111
MOCK_COMPLETION_POS.column,
12+
'',
1213
);
1314
expect(formatter).toBeInstanceOf(CompletionFormatter);
1415
});
1516
});
1617

1718
describe('removeInvalidLineBreaks', () => {
1819
it('should remove trailing line breaks', () => {
19-
const formatter = CompletionFormatter.create(
20+
const formatter = new CompletionFormatter(
2021
'function sum(a, b) {\n return a + b;\n}\n\n',
2122
MOCK_COMPLETION_POS.column,
23+
'',
2224
);
2325
const result = formatter.removeInvalidLineBreaks().build();
2426
expect(result).toBe('function sum(a, b) {\n return a + b;\n}');
2527
});
2628

2729
it('should not remove line breaks in the middle of the text', () => {
28-
const formatter = CompletionFormatter.create(
30+
const formatter = new CompletionFormatter(
2931
'const x = 5;\nconst y = 10;\nconst sum = x + y;',
3032
MOCK_COMPLETION_POS.column,
33+
'',
3134
);
3235
const result = formatter.removeInvalidLineBreaks().build();
3336
expect(result).toBe('const x = 5;\nconst y = 10;\nconst sum = x + y;');
3437
});
3538

3639
it('should handle empty string', () => {
37-
const formatter = CompletionFormatter.create(
40+
const formatter = new CompletionFormatter(
3841
'',
3942
MOCK_COMPLETION_POS.column,
43+
'',
4044
);
4145
const result = formatter.removeInvalidLineBreaks().build();
4246
expect(result).toBe('');
@@ -45,18 +49,20 @@ describe('CompletionFormatter', () => {
4549

4650
describe('removeMarkdownCodeSyntax', () => {
4751
it('should remove markdown code block syntax', () => {
48-
const formatter = CompletionFormatter.create(
52+
const formatter = new CompletionFormatter(
4953
'```\nconst array = [1, 2, 3];\narray.map(x => x * 2);\n```',
5054
MOCK_COMPLETION_POS.column,
55+
'',
5156
);
5257
const result = formatter.removeMarkdownCodeSyntax().build();
5358
expect(result).toBe('const array = [1, 2, 3];\narray.map(x => x * 2);');
5459
});
5560

5661
it('should remove multiple markdown code blocks', () => {
57-
const formatter = CompletionFormatter.create(
62+
const formatter = new CompletionFormatter(
5863
'```\nfunction greet(name) {\n return `Hello, ${name}!`;\n}\n```\nSome text\n```\nconst result = greet("Alice");\nconsole.log(result);\n```',
5964
MOCK_COMPLETION_POS.column,
65+
'',
6066
);
6167
const result = formatter.removeMarkdownCodeSyntax().build();
6268
expect(result).toBe(
@@ -65,9 +71,10 @@ describe('CompletionFormatter', () => {
6571
});
6672

6773
it('should handle code blocks with language specifiers', () => {
68-
const formatter = CompletionFormatter.create(
74+
const formatter = new CompletionFormatter(
6975
'```javascript\nclass Person {\n constructor(name) {\n this.name = name;\n }\n}\n```',
7076
MOCK_COMPLETION_POS.column,
77+
'',
7178
);
7279
const result = formatter.removeMarkdownCodeSyntax().build();
7380
expect(result).toBe(
@@ -76,27 +83,30 @@ describe('CompletionFormatter', () => {
7683
});
7784

7885
it('should not modify text without code blocks', () => {
79-
const formatter = CompletionFormatter.create(
86+
const formatter = new CompletionFormatter(
8087
'const PI = 3.14159;',
8188
MOCK_COMPLETION_POS.column,
89+
'',
8290
);
8391
const result = formatter.removeMarkdownCodeSyntax().build();
8492
expect(result).toBe('const PI = 3.14159;');
8593
});
8694

8795
it('should handle empty string', () => {
88-
const formatter = CompletionFormatter.create(
96+
const formatter = new CompletionFormatter(
8997
'',
9098
MOCK_COMPLETION_POS.column,
99+
'',
91100
);
92101
const result = formatter.removeMarkdownCodeSyntax().build();
93102
expect(result).toBe('');
94103
});
95104

96105
it('should handle incomplete code blocks', () => {
97-
const formatter = CompletionFormatter.create(
106+
const formatter = new CompletionFormatter(
98107
'```\nconst incomplete = true;',
99108
MOCK_COMPLETION_POS.column,
109+
'',
100110
);
101111
const result = formatter.removeMarkdownCodeSyntax().build();
102112
expect(result).toBe('```\nconst incomplete = true;');
@@ -105,9 +115,10 @@ describe('CompletionFormatter', () => {
105115

106116
describe('removeExcessiveNewlines', () => {
107117
it('should replace three or more consecutive newlines with two newlines', () => {
108-
const formatter = CompletionFormatter.create(
118+
const formatter = new CompletionFormatter(
109119
'import React from "react";\n\n\n\nconst App = () => {\n return <div>Hello React</div>;\n};',
110120
MOCK_COMPLETION_POS.column,
121+
'',
111122
);
112123
const result = formatter.removeExcessiveNewlines().build();
113124
expect(result).toBe(
@@ -116,18 +127,20 @@ describe('CompletionFormatter', () => {
116127
});
117128

118129
it('should not modify text with two or fewer consecutive newlines', () => {
119-
const formatter = CompletionFormatter.create(
130+
const formatter = new CompletionFormatter(
120131
'const x = 10;\n\nconst y = 20;',
121132
MOCK_COMPLETION_POS.column,
133+
'',
122134
);
123135
const result = formatter.removeExcessiveNewlines().build();
124136
expect(result).toBe('const x = 10;\n\nconst y = 20;');
125137
});
126138

127139
it('should handle multiple occurrences of excessive newlines', () => {
128-
const formatter = CompletionFormatter.create(
140+
const formatter = new CompletionFormatter(
129141
'function add(a, b) {\n return a + b;\n}\n\n\nfunction subtract(a, b) {\n return a - b;\n}\n\n\n\nconst result = add(5, 3);',
130142
MOCK_COMPLETION_POS.column,
143+
'',
131144
);
132145
const result = formatter.removeExcessiveNewlines().build();
133146
expect(result).toBe(
@@ -136,18 +149,20 @@ describe('CompletionFormatter', () => {
136149
});
137150

138151
it('should handle empty string', () => {
139-
const formatter = CompletionFormatter.create(
152+
const formatter = new CompletionFormatter(
140153
'',
141154
MOCK_COMPLETION_POS.column,
155+
'',
142156
);
143157
const result = formatter.removeExcessiveNewlines().build();
144158
expect(result).toBe('');
145159
});
146160

147161
it('should handle string with only newlines', () => {
148-
const formatter = CompletionFormatter.create(
162+
const formatter = new CompletionFormatter(
149163
'\n\n\n\n',
150164
MOCK_COMPLETION_POS.column,
165+
'',
151166
);
152167
const result = formatter.removeExcessiveNewlines().build();
153168
expect(result).toBe('\n\n');
@@ -156,43 +171,56 @@ describe('CompletionFormatter', () => {
156171

157172
describe('indentByColumn', () => {
158173
it('should indent subsequent lines by the current column position', () => {
159-
const formatter = CompletionFormatter.create(
174+
const formatter = new CompletionFormatter(
160175
'const numbers = [\n1,\n2,\n3\n];',
161176
4,
177+
'',
162178
);
163179
const result = formatter.indentByColumn().build();
164180
expect(result).toBe('const numbers = [\n 1,\n 2,\n 3\n ];');
165181
});
166182

167183
it('should not modify single line text', () => {
168-
const formatter = CompletionFormatter.create('const x = 42;', 3);
184+
const formatter = new CompletionFormatter('const x = 42;', 3, '');
169185
const result = formatter.indentByColumn().build();
170186
expect(result).toBe('const x = 42;');
171187
});
172188

173189
it('should handle empty string', () => {
174-
const formatter = CompletionFormatter.create('', 5);
190+
const formatter = new CompletionFormatter('', 5, '');
175191
const result = formatter.indentByColumn().build();
176192
expect(result).toBe('');
177193
});
178194

179195
it('should handle text with existing indentation', () => {
180-
const formatter = CompletionFormatter.create(
196+
const formatter = new CompletionFormatter(
181197
'function test() {\n const x = 1;\n return x;\n}',
182198
6,
199+
'',
183200
);
184201
const result = formatter.indentByColumn().build();
185202
expect(result).toBe(
186203
'function test() {\n const x = 1;\n return x;\n }',
187204
);
188205
});
206+
207+
it('should not indent when there is text before cursor in same line', () => {
208+
const formatter = new CompletionFormatter(
209+
'= [\n1,\n2\n];',
210+
8,
211+
'const x ',
212+
);
213+
const result = formatter.indentByColumn().build();
214+
expect(result).toBe('= [\n1,\n2\n];');
215+
});
189216
});
190217

191218
describe('build', () => {
192219
it('should return the formatted completion', () => {
193-
const formatter = CompletionFormatter.create(
220+
const formatter = new CompletionFormatter(
194221
' const square = (x) => x * x; ',
195222
MOCK_COMPLETION_POS.column,
223+
'',
196224
);
197225
const result = formatter.build();
198226
expect(result).toBe(' const square = (x) => x * x; ');
@@ -201,9 +229,10 @@ describe('CompletionFormatter', () => {
201229

202230
describe('chaining methods', () => {
203231
it('should allow chaining of multiple formatting methods', () => {
204-
const formatter = CompletionFormatter.create(
232+
const formatter = new CompletionFormatter(
205233
'```\nconst fruits = ["apple", "banana", "orange"];\nconst upperFruits = fruits.map(fruit => fruit.toUpperCase());\n```\n\n\n\nconsole.log(upperFruits);',
206234
MOCK_COMPLETION_POS.column,
235+
'',
207236
);
208237
const result = formatter
209238
.removeMarkdownCodeSyntax()
@@ -216,9 +245,10 @@ describe('CompletionFormatter', () => {
216245
});
217246

218247
it('should handle empty string with all formatting methods', () => {
219-
const formatter = CompletionFormatter.create(
248+
const formatter = new CompletionFormatter(
220249
'',
221250
MOCK_COMPLETION_POS.column,
251+
'',
222252
);
223253
const result = formatter
224254
.removeMarkdownCodeSyntax()

0 commit comments

Comments
 (0)