Skip to content

Commit a37fdd6

Browse files
adding some tests of the editor
1 parent d96e478 commit a37fdd6

File tree

2 files changed

+178
-44
lines changed

2 files changed

+178
-44
lines changed

playground/internal/editor/editor.go

Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ func (ce *codeEditor) handleTab(shift, ctrl bool) bool {
7070
return true
7171
}
7272

73+
startLine, endLine := ce.getSelectedLines()
74+
containsOnlyBlankLines := ce.foreachLine(startLine, endLine,
75+
func(line string, start, end int) bool { return trimLeftSpace(line) == `` })
76+
if containsOnlyBlankLines {
77+
// Nothing to indent or un-indent.
78+
return true
79+
}
80+
7381
if shift {
7482
// Handle Shift+Tab for un-indenting the current line.
7583
// TODO(grantnelson-wf): Implement
@@ -149,72 +157,95 @@ func (ce *codeEditor) handleSave(shift, ctrl bool) bool {
149157
return true
150158
}
151159

160+
const commentPrefix = `// `
161+
152162
// handleCommentToggle handles toggling comments on the current line or selection.
153163
func (ce *codeEditor) handleCommentToggle(shift, ctrl bool) bool {
154164
if !ctrl || shift {
155165
// Allow default behavior for '/' without a Ctrl or Shift+/.
156166
return false
157167
}
158168

159-
const commentPrefix = `// `
160-
161169
startLine, endLine := ce.getSelectedLines()
162-
leastIndent := -1
163-
nonBlankLineCount := 0
170+
containsOnlyBlankLines := true
171+
containsUncommentedLine := false
164172
ce.foreachLine(startLine, endLine, func(line string, start, end int) bool {
165173
if trimmed := trimLeftSpace(line); trimmed != `` {
166-
indent := len(line) - len(trimmed)
167-
if leastIndent < 0 || indent < leastIndent {
168-
leastIndent = indent
174+
containsOnlyBlankLines = false
175+
if !strings.HasPrefix(trimmed, commentPrefix) {
176+
containsUncommentedLine = true
177+
return false
169178
}
170-
nonBlankLineCount++
171179
}
172180
return true
173181
})
174182

175-
if nonBlankLineCount <= 0 {
176-
// No non-blank lines, nothing to comment/uncomment.
183+
if containsOnlyBlankLines {
184+
// Nothing to comment or uncomment.
177185
return true
178186
}
179187

180-
containsUncommentedLine := false
188+
if containsUncommentedLine {
189+
ce.addCommenting(startLine, endLine)
190+
return true
191+
}
192+
193+
ce.removeCommenting(startLine, endLine)
194+
return true
195+
}
196+
197+
// addCommenting will add the comment prefix to each non-blank line in
198+
// the given range including any lines that already are commented.
199+
func (ce *codeEditor) addCommenting(startLine, endLine int) {
200+
leastIndent := -1
181201
ce.foreachLine(startLine, endLine, func(line string, start, end int) bool {
182-
trimmed := strings.TrimSpace(line)
183-
if trimmed != `` && !strings.HasPrefix(trimmed, commentPrefix) {
184-
containsUncommentedLine = true
202+
if trimmed := trimLeftSpace(line); trimmed != `` {
203+
if indent := len(line) - len(trimmed); leastIndent < 0 || indent < leastIndent {
204+
leastIndent = indent
205+
}
185206
}
186207
return true
187208
})
188209

189-
if containsUncommentedLine {
190-
// Comment the selected lines including any commented lines.
191-
code := ce.Code()[:startLine]
192-
ce.foreachLine(startLine, endLine, func(line string, start, end int) bool {
193-
if line == "\n" || strings.TrimSpace(line) == `` {
194-
code += line // Empty line, just add as-is.
195-
return true
196-
}
197-
code += line[:leastIndent] + commentPrefix + line[leastIndent:]
210+
selStart, selEnd := ce.GetSelection()
211+
newStart, newEnd := selStart, selEnd
212+
code := ce.Code()[:startLine]
213+
ce.foreachLine(startLine, endLine, func(line string, start, end int) bool {
214+
if strings.TrimSpace(line) == `` {
215+
code += line // Empty line, just add as-is.
198216
return true
199-
})
200-
code += ce.Code()[endLine:]
201-
202-
start, end := ce.GetSelection()
203-
// TODO(grantnelson-wf): Handle when the end or start ends up before the comment prefix.
204-
newStart := start + len(commentPrefix)
205-
newEnd := end + len(commentPrefix)*nonBlankLineCount
206-
207-
ce.SetCode(code)
208-
ce.SetSelection(newStart, newEnd, code)
217+
}
218+
if selStart > start+leastIndent {
219+
newStart += len(commentPrefix)
220+
}
221+
if selEnd > start+leastIndent {
222+
newEnd += len(commentPrefix)
223+
}
224+
code += line[:leastIndent] + commentPrefix + line[leastIndent:]
209225
return true
210-
}
226+
})
227+
code += ce.Code()[endLine:]
228+
229+
ce.SetCode(code)
230+
ce.SetSelection(newStart, newEnd, code)
231+
}
211232

212-
// Uncomment any line that starts with the comment prefix (and preceding whitespace).
233+
// removeCommenting will uncomment any line that starts with the comment prefix
234+
// (and preceding whitespace).
235+
func (ce *codeEditor) removeCommenting(startLine, endLine int) {
236+
selStart, selEnd := ce.GetSelection()
237+
newStart, newEnd := selStart, selEnd
213238
code := ce.Code()[:startLine]
214239
ce.foreachLine(startLine, endLine, func(line string, start, end int) bool {
215240
if trimmed := trimLeftSpace(line); trimmed != `` {
216241
if index := strings.Index(line, commentPrefix); index >= 0 {
217242
code += line[:index] + line[index+len(commentPrefix):]
243+
if selStart > start+index {
244+
newStart -= len(commentPrefix)
245+
}
246+
if selEnd > start+index {
247+
newEnd -= len(commentPrefix)
248+
}
218249
return true
219250
}
220251
}
@@ -223,14 +254,8 @@ func (ce *codeEditor) handleCommentToggle(shift, ctrl bool) bool {
223254
})
224255
code += ce.Code()[endLine:]
225256

226-
start, end := ce.GetSelection()
227-
// TODO(grantnelson-wf): Handle when the end or start ends up before the comment prefix.
228-
newStart := start - len(commentPrefix)
229-
newEnd := end - len(commentPrefix)*nonBlankLineCount
230-
231257
ce.SetCode(code)
232258
ce.SetSelection(newStart, newEnd, code)
233-
return true
234259
}
235260

236261
// getSelectedLines returns the start and end character indices of that
@@ -246,7 +271,7 @@ func (ce *codeEditor) getSelectedLines() (int, int) {
246271
startLine := 0
247272
if start >= 0 && start <= codeLen {
248273
startLine = strings.LastIndex(code[:start], "\n") + 1
249-
if startLine < 0 {
274+
if startLine <= 0 {
250275
startLine = 0
251276
}
252277
}

playground/internal/editor/editor_test.go

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ func Test_Editor_ProcessKeyDown_Tab(t *testing.T) {
4949
// TODO: Add more tests for other Tab cases.
5050
}
5151

52+
// TODO(grantnelson-wf): Add tests for findMatchingOpeningBrace
53+
5254
func Test_Editor_ProcessKeyDown_Newline(t *testing.T) {
5355
runKeyDownTest(t, testKeyDown{
5456
name: `with ctrl does default`,
@@ -447,7 +449,7 @@ func Test_Editor_ProcessKeyDown_CommentToggle(t *testing.T) {
447449
})
448450

449451
runKeyDownTest(t, testKeyDown{
450-
name: `remove comments`,
452+
name: `uncomment lines`,
451453
code: lines(
452454
`func main() {`,
453455
` // // The following is always true`,
@@ -473,7 +475,114 @@ func Test_Editor_ProcessKeyDown_CommentToggle(t *testing.T) {
473475
wantPrefentDefault: true,
474476
})
475477

476-
// TODO(grantnelson-wf): Add more tests
478+
runKeyDownTest(t, testKeyDown{
479+
name: `uncomment with blank line`,
480+
code: lines(
481+
`func main() {`,
482+
` // if true {`,
483+
` `,
484+
` // fmt.Println("Hello")`,
485+
` }`,
486+
`}`),
487+
key: `/`,
488+
ctrl: true,
489+
selectionStart: 21, // before `true`
490+
selectionEnd: 39, // after `fmt`
491+
wantCode: lines(
492+
`func main() {`,
493+
` if true {`,
494+
` `,
495+
` fmt.Println("Hello")`,
496+
` }`,
497+
`}`),
498+
wantSelectionStart: 18, // selection adjusted for removed `// `s
499+
wantSelectionEnd: 33,
500+
wantPrefentDefault: true,
501+
})
502+
503+
runKeyDownTest(t, testKeyDown{
504+
name: `comment caret`,
505+
code: lines(
506+
`func main() {`,
507+
` fmt.Println("Hello")`,
508+
`}`),
509+
key: `/`,
510+
ctrl: true,
511+
selectionStart: 18, // after `fmt`
512+
selectionEnd: 18,
513+
wantCode: lines(
514+
`func main() {`,
515+
` // fmt.Println("Hello")`,
516+
`}`),
517+
wantSelectionStart: 21, // selection adjusted for added `// `s
518+
wantSelectionEnd: 21,
519+
wantPrefentDefault: true,
520+
})
521+
522+
runKeyDownTest(t, testKeyDown{
523+
name: `uncomment caret`,
524+
code: lines(
525+
`func main() {`,
526+
` // fmt.Println("Hello")`,
527+
`}`),
528+
key: `/`,
529+
ctrl: true,
530+
selectionStart: 21, // after `fmt`
531+
selectionEnd: 21,
532+
wantCode: lines(
533+
`func main() {`,
534+
` fmt.Println("Hello")`,
535+
`}`),
536+
wantSelectionStart: 18, // selection adjusted for removed `// `s
537+
wantSelectionEnd: 18,
538+
wantPrefentDefault: true,
539+
})
540+
541+
runKeyDownTest(t, testKeyDown{
542+
name: `comment only moves selection if after changes`,
543+
code: lines(
544+
`func main() {`,
545+
` if true {`,
546+
` fmt.Println("Hello")`,
547+
` }`,
548+
`}`),
549+
key: `/`,
550+
ctrl: true,
551+
selectionStart: 14, // at front of line 2
552+
selectionEnd: 48, // at front of line 4
553+
wantCode: lines(
554+
`func main() {`,
555+
` // if true {`,
556+
` // fmt.Println("Hello")`,
557+
` // }`,
558+
`}`),
559+
wantSelectionStart: 14, // before added `// `s
560+
wantSelectionEnd: 54, // before last added `// `s
561+
wantPrefentDefault: true,
562+
})
563+
564+
runKeyDownTest(t, testKeyDown{
565+
name: `uncomment only moves selection if after changes`,
566+
code: lines(
567+
`func main() {`,
568+
` // if true {`,
569+
` // fmt.Println("Hello")`,
570+
` // }`,
571+
`}`),
572+
key: `/`,
573+
ctrl: true,
574+
selectionStart: 14, // at front of line 2
575+
selectionEnd: 54, // at front of line 4
576+
wantCode: lines(
577+
`func main() {`,
578+
` if true {`,
579+
` fmt.Println("Hello")`,
580+
` }`,
581+
`}`),
582+
wantSelectionStart: 14, // before added `// `s
583+
wantSelectionEnd: 48, // before last added `// `s
584+
wantPrefentDefault: true,
585+
})
477586
}
478587

479588
func Test_Editor_ProcessKeyDown_Callback(t *testing.T) {

0 commit comments

Comments
 (0)