diff --git a/changelog/2024-08-supportArbitraryInsertionDelimiterDrinkFloat.md b/changelog/2024-08-supportArbitraryInsertionDelimiterDrinkFloat.md new file mode 100644 index 0000000000..9ab1953266 --- /dev/null +++ b/changelog/2024-08-supportArbitraryInsertionDelimiterDrinkFloat.md @@ -0,0 +1,6 @@ +--- +tags: [enhancement] +pullRequest: 2646 +--- + +`drop`, `float` and `puff` now behave like `drink` and `pour` for non-line targets: for example, `"puff token"` will insert spaces around the token; `"float item"` will insert `,`s as needed, and so on. diff --git a/data/fixtures/recorded/actions/insertEmptyLines/dropToken.yml b/data/fixtures/recorded/actions/insertEmptyLines/dropToken.yml new file mode 100644 index 0000000000..20853767bb --- /dev/null +++ b/data/fixtures/recorded/actions/insertEmptyLines/dropToken.yml @@ -0,0 +1,30 @@ +languageId: plaintext +command: + version: 7 + spokenForm: drop token + action: + name: insertEmptyLineBefore + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true +initialState: + documentContents: foo + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: " foo" + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 0, character: 1} + end: {line: 0, character: 4} + isReversed: false + hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatThis.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatThis.yml index c721912a29..9600fb624f 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/floatThis.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatThis.yml @@ -18,13 +18,13 @@ finalState: documentContents: |+ selections: - - anchor: {line: 1, character: 0} - active: {line: 1, character: 0} + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} thatMark: - type: UntypedTarget contentRange: - start: {line: 1, character: 0} - end: {line: 1, character: 0} + start: {line: 0, character: 0} + end: {line: 0, character: 0} isReversed: false hasExplicitRange: true ide: diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatThis10.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatThis10.yml index ae64ea3c58..a54fe374a2 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/floatThis10.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatThis10.yml @@ -21,13 +21,13 @@ finalState: hello selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 9} + end: {line: 1, character: 9} isReversed: false hasExplicitRange: true ide: diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatThis2.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatThis2.yml index cf2fe24010..db7b4dd629 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/floatThis2.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatThis2.yml @@ -18,13 +18,13 @@ finalState: documentContents: | hello selections: - - anchor: {line: 1, character: 0} - active: {line: 1, character: 0} + - anchor: {line: 0, character: 5} + active: {line: 0, character: 5} thatMark: - type: UntypedTarget contentRange: - start: {line: 1, character: 0} - end: {line: 1, character: 0} + start: {line: 0, character: 5} + end: {line: 0, character: 5} isReversed: false hasExplicitRange: true ide: diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatThis3.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatThis3.yml index d45eeab965..6d80e2f801 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/floatThis3.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatThis3.yml @@ -18,13 +18,13 @@ finalState: documentContents: |2 hello selections: - - anchor: {line: 1, character: 0} - active: {line: 1, character: 0} + - anchor: {line: 0, character: 9} + active: {line: 0, character: 9} thatMark: - type: UntypedTarget contentRange: - start: {line: 1, character: 0} - end: {line: 1, character: 0} + start: {line: 0, character: 9} + end: {line: 0, character: 9} isReversed: false hasExplicitRange: true ide: diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatThis4.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatThis4.yml index 19e96cb1dd..260980210c 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/floatThis4.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatThis4.yml @@ -18,13 +18,13 @@ finalState: documentContents: |2 selections: - - anchor: {line: 1, character: 0} - active: {line: 1, character: 0} + - anchor: {line: 0, character: 4} + active: {line: 0, character: 4} thatMark: - type: UntypedTarget contentRange: - start: {line: 1, character: 0} - end: {line: 1, character: 0} + start: {line: 0, character: 4} + end: {line: 0, character: 4} isReversed: false hasExplicitRange: true ide: diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatThis5.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatThis5.yml index c28303dbb5..a4fb8ec563 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/floatThis5.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatThis5.yml @@ -21,13 +21,13 @@ finalState: whatever hello selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 9} + end: {line: 1, character: 9} isReversed: false hasExplicitRange: true ide: diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatThis6.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatThis6.yml index 614dd28818..a566efb556 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/floatThis6.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatThis6.yml @@ -21,13 +21,13 @@ finalState: whatever hello selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 5} + active: {line: 1, character: 5} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 5} + end: {line: 1, character: 5} isReversed: false hasExplicitRange: true ide: diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatThis7.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatThis7.yml index d6142c7b18..8516c8ebe1 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/floatThis7.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatThis7.yml @@ -20,13 +20,13 @@ finalState: hello selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 0} + end: {line: 1, character: 0} isReversed: false hasExplicitRange: true ide: diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatThis8.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatThis8.yml index 1ab0e331f3..f0b2208dce 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/floatThis8.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatThis8.yml @@ -20,13 +20,13 @@ finalState: hello selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 0} + end: {line: 1, character: 0} isReversed: false hasExplicitRange: true ide: diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatThis9.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatThis9.yml index 2a4d2270ed..c8c7ebca34 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/floatThis9.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatThis9.yml @@ -21,13 +21,13 @@ finalState: hello selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 4} + end: {line: 1, character: 4} isReversed: false hasExplicitRange: true ide: diff --git a/data/fixtures/recorded/actions/insertEmptyLines/floatToken.yml b/data/fixtures/recorded/actions/insertEmptyLines/floatToken.yml new file mode 100644 index 0000000000..ed96c48d22 --- /dev/null +++ b/data/fixtures/recorded/actions/insertEmptyLines/floatToken.yml @@ -0,0 +1,30 @@ +languageId: plaintext +command: + version: 7 + spokenForm: float token + action: + name: insertEmptyLineAfter + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true +initialState: + documentContents: foo + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: "foo " + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 0, character: 0} + end: {line: 0, character: 3} + isReversed: false + hasExplicitRange: true diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis.yml index cca933c0e2..f4628a4987 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis.yml @@ -19,18 +19,18 @@ finalState: selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 0, character: 0} + end: {line: 0, character: 0} isReversed: false hasExplicitRange: true ide: flashes: - style: justAdded - range: {type: line, start: 1, end: 1} + range: {type: line, start: 0, end: 0} - style: justAdded range: {type: line, start: 1, end: 1} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis10.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis10.yml index c1e2203751..7e3b6ec6f3 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis10.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis10.yml @@ -22,13 +22,13 @@ finalState: selections: - - anchor: {line: 3, character: 0} - active: {line: 3, character: 0} + - anchor: {line: 2, character: 4} + active: {line: 2, character: 4} thatMark: - type: UntypedTarget contentRange: - start: {line: 3, character: 0} - end: {line: 3, character: 0} + start: {line: 2, character: 4} + end: {line: 2, character: 4} isReversed: false hasExplicitRange: true ide: @@ -36,4 +36,4 @@ ide: - style: justAdded range: {type: line, start: 1, end: 1} - style: justAdded - range: {type: line, start: 2, end: 2} + range: {type: line, start: 3, end: 3} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis11.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis11.yml index 112dd8bf5f..f1cf982414 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis11.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis11.yml @@ -22,13 +22,13 @@ finalState: hello selections: - - anchor: {line: 3, character: 0} - active: {line: 3, character: 0} + - anchor: {line: 2, character: 9} + active: {line: 2, character: 9} thatMark: - type: UntypedTarget contentRange: - start: {line: 3, character: 0} - end: {line: 3, character: 0} + start: {line: 2, character: 9} + end: {line: 2, character: 9} isReversed: false hasExplicitRange: true ide: @@ -36,4 +36,4 @@ ide: - style: justAdded range: {type: line, start: 1, end: 1} - style: justAdded - range: {type: line, start: 2, end: 2} + range: {type: line, start: 3, end: 3} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis19.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis19.yml index 3bc5e6cbaa..6d828e7229 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis19.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis19.yml @@ -23,13 +23,13 @@ finalState: selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 0} + end: {line: 1, character: 0} isReversed: false hasExplicitRange: true ide: @@ -37,4 +37,4 @@ ide: - style: justAdded range: {type: line, start: 1, end: 1} - style: justAdded - range: {type: line, start: 3, end: 3} + range: {type: line, start: 2, end: 2} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis2.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis2.yml index 60d96f16a3..1b042ffb67 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis2.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis2.yml @@ -19,13 +19,13 @@ finalState: hello selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 5} + active: {line: 1, character: 5} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 5} + end: {line: 1, character: 5} isReversed: false hasExplicitRange: true ide: @@ -33,4 +33,4 @@ ide: - style: justAdded range: {type: line, start: 0, end: 0} - style: justAdded - range: {type: line, start: 1, end: 1} + range: {type: line, start: 2, end: 2} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis20.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis20.yml index 67003a258c..a553033c80 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis20.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis20.yml @@ -25,13 +25,13 @@ finalState: there selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 0} + end: {line: 1, character: 0} isReversed: false hasExplicitRange: true ide: @@ -39,4 +39,4 @@ ide: - style: justAdded range: {type: line, start: 1, end: 1} - style: justAdded - range: {type: line, start: 3, end: 3} + range: {type: line, start: 2, end: 2} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis3.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis3.yml index 4ad694a160..2233f9c928 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis3.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis3.yml @@ -19,13 +19,13 @@ finalState: hello selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 9} + active: {line: 1, character: 9} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 9} + end: {line: 1, character: 9} isReversed: false hasExplicitRange: true ide: @@ -33,4 +33,4 @@ ide: - style: justAdded range: {type: line, start: 0, end: 0} - style: justAdded - range: {type: line, start: 1, end: 1} + range: {type: line, start: 2, end: 2} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis4.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis4.yml index f2ab6c3a1b..d857b8a6d0 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis4.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis4.yml @@ -19,13 +19,13 @@ finalState: selections: - - anchor: {line: 2, character: 0} - active: {line: 2, character: 0} + - anchor: {line: 1, character: 4} + active: {line: 1, character: 4} thatMark: - type: UntypedTarget contentRange: - start: {line: 2, character: 0} - end: {line: 2, character: 0} + start: {line: 1, character: 4} + end: {line: 1, character: 4} isReversed: false hasExplicitRange: true ide: @@ -33,4 +33,4 @@ ide: - style: justAdded range: {type: line, start: 0, end: 0} - style: justAdded - range: {type: line, start: 1, end: 1} + range: {type: line, start: 2, end: 2} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis5.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis5.yml index 726442ef5b..8011895354 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis5.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis5.yml @@ -22,13 +22,13 @@ finalState: hello selections: - - anchor: {line: 3, character: 0} - active: {line: 3, character: 0} + - anchor: {line: 2, character: 9} + active: {line: 2, character: 9} thatMark: - type: UntypedTarget contentRange: - start: {line: 3, character: 0} - end: {line: 3, character: 0} + start: {line: 2, character: 9} + end: {line: 2, character: 9} isReversed: false hasExplicitRange: true ide: @@ -36,4 +36,4 @@ ide: - style: justAdded range: {type: line, start: 1, end: 1} - style: justAdded - range: {type: line, start: 2, end: 2} + range: {type: line, start: 3, end: 3} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis6.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis6.yml index 68269a09d2..2d12891b45 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis6.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis6.yml @@ -22,13 +22,13 @@ finalState: hello selections: - - anchor: {line: 3, character: 0} - active: {line: 3, character: 0} + - anchor: {line: 2, character: 5} + active: {line: 2, character: 5} thatMark: - type: UntypedTarget contentRange: - start: {line: 3, character: 0} - end: {line: 3, character: 0} + start: {line: 2, character: 5} + end: {line: 2, character: 5} isReversed: false hasExplicitRange: true ide: @@ -36,4 +36,4 @@ ide: - style: justAdded range: {type: line, start: 1, end: 1} - style: justAdded - range: {type: line, start: 2, end: 2} + range: {type: line, start: 3, end: 3} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis7.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis7.yml index 5e7a60856f..1c7c33da26 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis7.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis7.yml @@ -36,4 +36,4 @@ ide: - style: justAdded range: {type: line, start: 1, end: 1} - style: justAdded - range: {type: line, start: 2, end: 2} + range: {type: line, start: 3, end: 3} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis8.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis8.yml index 4c7a21332c..25e9a3dfa5 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis8.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis8.yml @@ -21,18 +21,18 @@ finalState: selections: - - anchor: {line: 3, character: 0} - active: {line: 3, character: 0} + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} thatMark: - type: UntypedTarget contentRange: - start: {line: 3, character: 0} - end: {line: 3, character: 0} + start: {line: 1, character: 0} + end: {line: 1, character: 0} isReversed: false hasExplicitRange: true ide: flashes: - style: justAdded - range: {type: line, start: 2, end: 2} + range: {type: line, start: 1, end: 1} - style: justAdded range: {type: line, start: 2, end: 2} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffThis9.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffThis9.yml index d3ac84354e..812d003649 100644 --- a/data/fixtures/recorded/actions/insertEmptyLines/puffThis9.yml +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffThis9.yml @@ -21,18 +21,18 @@ finalState: selections: - - anchor: {line: 3, character: 0} - active: {line: 3, character: 0} + - anchor: {line: 1, character: 0} + active: {line: 1, character: 0} thatMark: - type: UntypedTarget contentRange: - start: {line: 3, character: 0} - end: {line: 3, character: 0} + start: {line: 1, character: 0} + end: {line: 1, character: 0} isReversed: false hasExplicitRange: true ide: flashes: - style: justAdded - range: {type: line, start: 2, end: 2} + range: {type: line, start: 1, end: 1} - style: justAdded range: {type: line, start: 2, end: 2} diff --git a/data/fixtures/recorded/actions/insertEmptyLines/puffToken.yml b/data/fixtures/recorded/actions/insertEmptyLines/puffToken.yml new file mode 100644 index 0000000000..6987b43948 --- /dev/null +++ b/data/fixtures/recorded/actions/insertEmptyLines/puffToken.yml @@ -0,0 +1,30 @@ +languageId: plaintext +command: + version: 7 + spokenForm: puff token + action: + name: insertEmptyLinesAround + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true +initialState: + documentContents: foo + selections: + - anchor: {line: 0, character: 0} + active: {line: 0, character: 0} + marks: {} +finalState: + documentContents: " foo " + selections: + - anchor: {line: 0, character: 1} + active: {line: 0, character: 1} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 0, character: 1} + end: {line: 0, character: 4} + isReversed: false + hasExplicitRange: true diff --git a/packages/common/src/types/GeneralizedRange.ts b/packages/common/src/types/GeneralizedRange.ts index e89bd924de..bdb7368eab 100644 --- a/packages/common/src/types/GeneralizedRange.ts +++ b/packages/common/src/types/GeneralizedRange.ts @@ -53,8 +53,8 @@ export function isLineRange(range: GeneralizedRange): range is LineRange { return range.type === "line"; } -export function toLineRange(range: Range): LineRange { - return { type: "line", start: range.start.line, end: range.end.line }; +export function toLineRange({ start, end }: Range): LineRange { + return { type: "line", start: start.line, end: end.line }; } export function toCharacterRange({ start, end }: Range): CharacterRange { diff --git a/packages/cursorless-engine/src/actions/Actions.ts b/packages/cursorless-engine/src/actions/Actions.ts index 1e975a5d9e..b8710ab46f 100644 --- a/packages/cursorless-engine/src/actions/Actions.ts +++ b/packages/cursorless-engine/src/actions/Actions.ts @@ -108,9 +108,18 @@ export class Actions implements ActionRecord { this.rangeUpdater, this.modifierStageFactory, ); - insertEmptyLineAfter = new InsertEmptyLineAfter(this.rangeUpdater); - insertEmptyLineBefore = new InsertEmptyLineBefore(this.rangeUpdater); - insertEmptyLinesAround = new InsertEmptyLinesAround(this.rangeUpdater); + insertEmptyLineAfter = new InsertEmptyLineAfter( + this.rangeUpdater, + this.modifierStageFactory, + ); + insertEmptyLineBefore = new InsertEmptyLineBefore( + this.rangeUpdater, + this.modifierStageFactory, + ); + insertEmptyLinesAround = new InsertEmptyLinesAround( + this.rangeUpdater, + this.modifierStageFactory, + ); insertSnippet = new InsertSnippet( this.rangeUpdater, this.snippets, diff --git a/packages/cursorless-engine/src/actions/InsertEmptyLines.ts b/packages/cursorless-engine/src/actions/InsertEmptyLines.ts index 8cc4551095..9f2607a292 100644 --- a/packages/cursorless-engine/src/actions/InsertEmptyLines.ts +++ b/packages/cursorless-engine/src/actions/InsertEmptyLines.ts @@ -1,65 +1,61 @@ -import { FlashStyle, Range, toLineRange } from "@cursorless/common"; -import { flatten } from "lodash-es"; +import { + FlashStyle, + RangeExpansionBehavior, + toCharacterRange, + toLineRange, + zipStrict, + type InsertionMode, +} from "@cursorless/common"; import type { RangeUpdater } from "../core/updateSelections/RangeUpdater"; import { performEditsAndUpdateSelections } from "../core/updateSelections/updateSelections"; +import { containingLineIfUntypedModifier } from "../processTargets/modifiers/commonContainingScopeIfUntypedModifiers"; +import type { ModifierStageFactory } from "../processTargets/ModifierStageFactory"; +import type { ModifierStage } from "../processTargets/PipelineStages.types"; import { ide } from "../singletons/ide.singleton"; import type { Target } from "../typings/target.types"; +import type { EditWithRangeUpdater as EditWithRangeType } from "../typings/Types"; import { runOnTargetsForEachEditor } from "../util/targetUtils"; import type { ActionReturnValue, SimpleAction } from "./actions.types"; -class InsertEmptyLines implements SimpleAction { +interface EditWithFlashType extends EditWithRangeType { + isLine: boolean; +} + +/** NB: this now also inserts insertion delimiters where appropriate, not just empty lines */ +abstract class InsertEmptyLines implements SimpleAction { + getFinalStages(): ModifierStage[] { + return [this.modifierStageFactory.create(containingLineIfUntypedModifier)]; + } + constructor( private rangeUpdater: RangeUpdater, - private insertAbove: boolean, - private insertBelow: boolean, + private modifierStageFactory: ModifierStageFactory, ) { this.run = this.run.bind(this); } - private getRanges(targets: Target[]) { - let lines = targets.flatMap((target) => { - const lines: number[] = []; - if (this.insertAbove) { - lines.push(target.contentRange.start.line); - } - if (this.insertBelow) { - lines.push(target.contentRange.end.line + 1); - } - return lines; - }); - // Remove duplicates - lines = [...new Set(lines)]; - - return lines.map((line) => new Range(line, 0, line, 0)); - } - - private getEdits(ranges: Range[]) { - return ranges.map((range) => ({ - range, - text: "\n", - })); - } - async run(targets: Target[]): Promise { - const results = flatten( - await runOnTargetsForEachEditor(targets, async (editor, targets) => { - const ranges = this.getRanges(targets); - const edits = this.getEdits(ranges); + const results = await runOnTargetsForEachEditor( + targets, + async (editor, targets) => { + const edits = this.getEdits(targets); const contentSelections = targets.map( (target) => target.thatTarget.contentSelection, ); - const editableEditor = ide().getEditableTextEditor(editor); const { contentSelections: updatedThatSelections, - ranges: lineSelections, + editRanges: updatedEditRanges, } = await performEditsAndUpdateSelections({ rangeUpdater: this.rangeUpdater, - editor: editableEditor, + editor: ide().getEditableTextEditor(editor), edits, selections: { contentSelections, - ranges, + editRanges: { + selections: edits.map((edit) => edit.range), + behavior: RangeExpansionBehavior.openOpen, + }, }, }); @@ -68,25 +64,23 @@ class InsertEmptyLines implements SimpleAction { editor, selection, })), - lineSelections: lineSelections.map((selection, index) => ({ - editor, - range: - ranges[index].start.line < editor.document.lineCount - 1 - ? new Range( - selection.start.translate(-1, undefined), - selection.end.translate(-1, undefined), - ) - : selection, - })), + flashRanges: zipStrict(edits, updatedEditRanges).map( + ([edit, editRange]) => ({ + editor, + // Exclude the new line delimiter from the range for line edits + range: edit.isLine ? edit.updateRange(editRange) : editRange, + isLine: edit.isLine, + }), + ), }; - }), + }, ); await ide().flashRanges( results.flatMap((result) => - result.lineSelections.map(({ editor, range }) => ({ + result.flashRanges.map(({ editor, range, isLine }) => ({ editor, - range: toLineRange(range), + range: isLine ? toLineRange(range) : toCharacterRange(range), style: FlashStyle.justAdded, })), ), @@ -96,22 +90,58 @@ class InsertEmptyLines implements SimpleAction { return { thatSelections: thatMark }; } + + protected abstract getEdits(targets: Target[]): EditWithFlashType[]; } export class InsertEmptyLinesAround extends InsertEmptyLines { - constructor(rangeUpdater: RangeUpdater) { - super(rangeUpdater, true, true); + constructor( + rangeUpdater: RangeUpdater, + modifierStageFactory: ModifierStageFactory, + ) { + super(rangeUpdater, modifierStageFactory); + } + + protected getEdits(targets: Target[]) { + return targets.flatMap((target) => [ + constructChangeEdit(target, "before"), + constructChangeEdit(target, "after"), + ]); } } export class InsertEmptyLineAbove extends InsertEmptyLines { - constructor(rangeUpdater: RangeUpdater) { - super(rangeUpdater, true, false); + constructor( + rangeUpdater: RangeUpdater, + modifierStageFactory: ModifierStageFactory, + ) { + super(rangeUpdater, modifierStageFactory); + } + + protected getEdits(targets: Target[]) { + return targets.map((target) => constructChangeEdit(target, "before")); } } export class InsertEmptyLineBelow extends InsertEmptyLines { - constructor(rangeUpdater: RangeUpdater) { - super(rangeUpdater, false, true); + constructor( + rangeUpdater: RangeUpdater, + modifierStageFactory: ModifierStageFactory, + ) { + super(rangeUpdater, modifierStageFactory); + } + + protected getEdits(targets: Target[]) { + return targets.map((target) => constructChangeEdit(target, "after")); } } + +function constructChangeEdit( + target: Target, + insertionMode: InsertionMode, +): EditWithFlashType { + return { + ...target.toDestination(insertionMode).constructChangeEdit("", true), + isLine: target.isLine, + }; +} diff --git a/packages/cursorless-engine/src/processTargets/targets/DestinationImpl.ts b/packages/cursorless-engine/src/processTargets/targets/DestinationImpl.ts index a76fe7836a..2c4a551b22 100644 --- a/packages/cursorless-engine/src/processTargets/targets/DestinationImpl.ts +++ b/packages/cursorless-engine/src/processTargets/targets/DestinationImpl.ts @@ -80,18 +80,24 @@ export class DestinationImpl implements Destination { return "edit"; } - constructChangeEdit(text: string): EditWithRangeUpdater { + constructChangeEdit( + text: string, + skipIndentation = false, + ): EditWithRangeUpdater { return this.insertionMode === "before" || this.insertionMode === "after" - ? this.constructEditWithDelimiters(text) + ? this.constructEditWithDelimiters(text, skipIndentation) : this.constructEditWithoutDelimiters(text); } - private constructEditWithDelimiters(text: string): EditWithRangeUpdater { + private constructEditWithDelimiters( + text: string, + skipIndentation: boolean, + ): EditWithRangeUpdater { const range = this.getEditRange(); - const editText = this.getEditText(text); + const editText = this.getEditText(text, skipIndentation); const updateRange = (range: Range) => { - return this.updateRange(range, text); + return this.updateRange(range, text, skipIndentation); }; return { @@ -134,19 +140,20 @@ export class DestinationImpl implements Destination { return new Range(position, position); } - private getEditText(text: string) { + private getEditText(text: string, skipIndentation: boolean) { + const indentationString = skipIndentation ? "" : this.indentationString; const insertionText = - this.indentationString + (this.insertionPrefix ?? "") + text; + indentationString + (this.insertionPrefix ?? "") + text; return this.isBefore ? insertionText + this.insertionDelimiter : this.insertionDelimiter + insertionText; } - private updateRange(range: Range, text: string) { + private updateRange(range: Range, text: string, skipIndentation: boolean) { const baseStartOffset = this.editor.document.offsetAt(range.start) + - this.indentationString.length + + (skipIndentation ? 0 : this.indentationString.length) + (this.insertionPrefix?.length ?? 0); const startIndex = this.isBefore diff --git a/packages/cursorless-engine/src/typings/target.types.ts b/packages/cursorless-engine/src/typings/target.types.ts index 1e54b9ce42..18178c57ae 100644 --- a/packages/cursorless-engine/src/typings/target.types.ts +++ b/packages/cursorless-engine/src/typings/target.types.ts @@ -216,5 +216,8 @@ export interface Destination { withTarget(target: Target): Destination; getEditNewActionType(): EditNewActionType; /** Constructs change/insertion edit. Adds delimiter before/after if needed */ - constructChangeEdit(text: string): EditWithRangeUpdater; + constructChangeEdit( + text: string, + skipIndentation?: boolean, + ): EditWithRangeUpdater; }