Skip to content

Commit

Permalink
Add trimEdit back so empty edits don't get made (#308)
Browse files Browse the repository at this point in the history
Also fixes some of the arithmetic, which was wrong. And converts Edit
into a class so it can have the .empty and .isEmpty members. The
Fable.Core.AttachMembers attribute is then needed so the property names
are not mangled in JS.
  • Loading branch information
stkb committed Feb 6, 2022
1 parent 5511097 commit 189d253
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 36 deletions.
4 changes: 2 additions & 2 deletions core/Main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ let strWidth tabSize str = Line.strWidth tabSize str
/// The client must supply the new text that was inserted in the edit, as well
/// as the position where it was inserted
let maybeAutoWrap file settings newText (pos: Position) (getLine: Func<int, string>) =
let noEdit = { startLine=0; endLine=0; lines = [||]; selections = [||] }
let noEdit = Edit.empty

if String.IsNullOrEmpty(newText) then noEdit
// If column < 1 we never wrap
Expand Down Expand Up @@ -75,4 +75,4 @@ let maybeAutoWrap file settings newText (pos: Position) (getLine: Func<int, stri
let afterPos =
if enterPressed then { line = line + 1; character = indent.Length }
else { line = line; character = char }
{ edit with selections = [| { anchor=afterPos; active=afterPos} |] }
edit.withSelections [| { anchor=afterPos; active=afterPos} |]
19 changes: 18 additions & 1 deletion core/Selections.fs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,22 @@ let rec private processBlocks : Context -> LineRange list -> ParseResult -> unit

loop selections parseResult.startLine parseResult.blocks parseResult.originalLines

/// Trims all unchanged lines from the start and end of an edit.
let private trimEdit (originalLines: Nonempty<string>) (edit : Edit) : Edit =
let originalLinesArray = originalLines |> Nonempty.toList |> List.toArray

let mutable s = 0
while s < edit.lines.Length && s <= edit.endLine - edit.startLine
&& originalLinesArray[edit.startLine + s] = edit.lines[s]
do s <- s + 1

let mutable e = 0
while e < edit.lines.Length - s && e <= edit.endLine - edit.startLine - s
&& originalLinesArray[edit.endLine - e] = edit.lines[edit.lines.Length - 1 - e]
do e <- e + 1

Edit (edit.startLine + s, edit.endLine - e,
Array.sub edit.lines s (edit.lines.Length - s - e), edit.selections)


let wrapSelected : Nonempty<string> -> Selection seq -> Context -> Edit =
Expand All @@ -191,4 +207,5 @@ let wrapSelected : Nonempty<string> -> Selection seq -> Context -> Edit =
let parseResult =
{startLine = 0; originalLines = originalLines; blocks = context.getBlocks()}
processBlocks context selectionRanges parseResult
{(context.output.toEdit ()) with selections = Seq.toArray selections}
let edit = context.output.toEdit () |> trimEdit originalLines
edit.withSelections (Seq.toArray selections)
53 changes: 26 additions & 27 deletions core/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,33 @@ type File = { language: string; path: string; getMarkers: Func<CustomMarkers> }

/// Settings passed in from the editor
type Settings = {
column : int
tabWidth : int
doubleSentenceSpacing : bool
reformat : bool
wholeComment : bool
column : int
tabWidth : int
doubleSentenceSpacing : bool
reformat : bool
wholeComment : bool
}

type Position = {
line : int
character : int
}

type Selection = {
anchor : Position
active : Position
}

/// Edit object to be passed out to the editor
type Edit = {
startLine : int
endLine : int
lines : array<string>
/// In a standard wrap this is the same as the selections passed in to
/// wrapping. For an auto-wrap this is the normal selection position for
/// after the just-done edit (before wrapping). These selections still need
/// adjusting to be in the expected places after a wrap (both clients do
/// this themselves). In the future we might do this in Core instead.
selections: array<Selection>
}
type Position = { line: int; character: int }

type Selection = { anchor: Position; active: Position }

/// Edit object to be passed out to the editor. If endLine < startLine and lines is empty,
/// then it's a no-op edit.
[<Fable.Core.AttachMembers>]
type Edit (startLine_, endLine_, lines_, selections_) =
member _.startLine : int = startLine_
member _.endLine : int = endLine_
member _.lines : array<string> = lines_
/// In a standard wrap this is the same as the selections passed in to wrapping. For an
/// auto-wrap this is the normal selection position for after the just-done edit (before
/// wrapping). These selections still need adjusting to be in the expected places after
/// a wrap (both clients do this themselves). In the future we might do this in Core
/// instead.
member _.selections : array<Selection> = selections_

member _.isEmpty = endLine_ < startLine_ && lines_.Length = 0
static member empty = Edit (0, -1, [||], [||])
member _.withSelections newSels = Edit (startLine_, endLine_, lines_, newSels)

type DocState = { filePath: string; version: int; selections: Selection[] }
4 changes: 1 addition & 3 deletions core/Wrapping.fs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,4 @@ type OutputBuffer(settings : Settings) =
linesConsumed <- linesConsumed + size contents

member _.toEdit () =
{ startLine = startLine; endLine = startLine + linesConsumed - 1
lines = List.toArray (List.rev outputLines); selections = [||]
}
Edit (startLine, startLine + linesConsumed - 1, List.toArray (List.rev outputLines), [||])
2 changes: 1 addition & 1 deletion vscode/src/AutoWrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const checkChange = async (e: TextDocumentChangeEvent) => {
// maybeAutoWrap does more checks: that newText isn't empty, but is only whitespace.
// Don't call this in a promise: it causes timing issues.
const edit = maybeAutoWrap(file, settings, newText, range.start, docLine(doc))
return editor.edit (builder => buildEdit(editor, builder, edit, false))
if (!edit.isEmpty) return editor.edit (builder => buildEdit(editor, builder, edit, false))
}
catch (err) { catchErr(err) }
}
Expand Down
2 changes: 1 addition & 1 deletion vscode/src/Common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const getDocState = (editor: TextEditor) : DocState => {
export function buildEdit
(editor: TextEditor, editBuilder: TextEditorEdit, edit: Edit, saveState: boolean) : void
{
if (!edit.lines.length) return
if (edit.isEmpty) return

const selections = edit.selections.map(vscodeSelection)
const doc = editor.document
Expand Down
4 changes: 3 additions & 1 deletion vscode/src/Core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ export interface DocType {
export interface Edit {
startLine: number
endLine: number
lines: string[]
lines: readonly string[]
selections: readonly Selection[]

isEmpty: boolean
}

export interface Position { line: number, character: number }
Expand Down

0 comments on commit 189d253

Please sign in to comment.