duplicate text editor
This commit is contained in:
3
projects/duplicate-text-editor/.gitignore
vendored
Normal file
3
projects/duplicate-text-editor/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
bin/
|
||||
*.vsix
|
||||
node_modules/
|
19
projects/duplicate-text-editor/.vscode/launch.json
vendored
Normal file
19
projects/duplicate-text-editor/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/*.js"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
13
projects/duplicate-text-editor/.vscode/tasks.json
vendored
Normal file
13
projects/duplicate-text-editor/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "hxml",
|
||||
"file": "build.hxml",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
6
projects/duplicate-text-editor/.vscodeignore
Normal file
6
projects/duplicate-text-editor/.vscodeignore
Normal file
@@ -0,0 +1,6 @@
|
||||
.vscode
|
||||
bin/*.map
|
||||
src
|
||||
build.hxml
|
||||
haxelib.json
|
||||
test.sh
|
20
projects/duplicate-text-editor/README.md
Normal file
20
projects/duplicate-text-editor/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# duplicate-text-editor
|
||||
|
||||
Sometimes you have to edit text that will be duplicated in multiple files. For example,
|
||||
when writing a tutorial which includes code snippets from an example project.
|
||||
|
||||
This VSCode extension lets you edit a text snippet simultaneously in every file where it occurs.
|
||||
|
||||
Like [LinkedEditingRanges](https://code.visualstudio.com/api/references/vscode-api#LinkedEditingRanges) but across multiple files and with no safety guarantees.
|
||||
|
||||
## Features
|
||||
|
||||
Attempts to be smart about cases where the snippet is indented differently in different files.
|
||||
|
||||
## Extension Settings
|
||||
|
||||
## Known Issues
|
||||
|
||||
Can't be used to de-indent a snippet.
|
||||
|
||||
## Release Notes
|
10
projects/duplicate-text-editor/build.hxml
Normal file
10
projects/duplicate-text-editor/build.hxml
Normal file
@@ -0,0 +1,10 @@
|
||||
-lib kiss-vscode-api
|
||||
-lib kiss
|
||||
-cp src
|
||||
-js bin/extension.js
|
||||
-dce full
|
||||
-D analyzer-optimize
|
||||
-D js-es=6
|
||||
-debug
|
||||
Main
|
||||
-cmd npx vsce package
|
2125
projects/duplicate-text-editor/package-lock.json
generated
Normal file
2125
projects/duplicate-text-editor/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
projects/duplicate-text-editor/package.json
Normal file
37
projects/duplicate-text-editor/package.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"main": "bin/extension.js",
|
||||
"name": "duplicate-text-editor",
|
||||
"description": "",
|
||||
"repository": {
|
||||
"url": "",
|
||||
"type:": "git"
|
||||
},
|
||||
"homepage": "",
|
||||
"categories": [],
|
||||
"extensionPack": [],
|
||||
"publisher": "",
|
||||
"contributes": {
|
||||
"keybindings": [
|
||||
{
|
||||
"command": "duplicate-text-editor.startEditingSelection",
|
||||
"mac": "Cmd+; Cmd+d",
|
||||
"key": "Ctrl+; Ctrl+d"
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"title": "duplicate-text-editor: Edit the currently selected text wherever it occurs in your workspace",
|
||||
"command": "duplicate-text-editor.startEditingSelection"
|
||||
}
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vsce": "^2.15.0"
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"activationEvents": [],
|
||||
"displayName": ""
|
||||
}
|
10
projects/duplicate-text-editor/src/Main.hx
Normal file
10
projects/duplicate-text-editor/src/Main.hx
Normal file
@@ -0,0 +1,10 @@
|
||||
import kiss.Prelude;
|
||||
import kiss.List;
|
||||
import haxe.Constraints;
|
||||
|
||||
import vscode.*;
|
||||
|
||||
using StringTools;
|
||||
|
||||
@:build(kiss.Kiss.build())
|
||||
class Main {}
|
97
projects/duplicate-text-editor/src/Main.kiss
Normal file
97
projects/duplicate-text-editor/src/Main.kiss
Normal file
@@ -0,0 +1,97 @@
|
||||
(loadFrom "kiss-vscode-api" "src/Util.kiss")
|
||||
(loadFrom "kiss-vscode-api" "src/KissUtil.kiss")
|
||||
|
||||
(function :kiss.List<Dynamic>->Bool matchesLine [ltrimmedLine]
|
||||
->[:Array<Dynamic> lineAndIndex]
|
||||
(let [[:Int index :String line] lineAndIndex]
|
||||
(= (line.ltrim) ltrimmedLine)))
|
||||
|
||||
(function :Null<Int> indentationDeltasMatch [:Array<String> indentation1 :Array<String>> indentation2]
|
||||
"If indentation follows the same pattern, return the first lowest level of the second one"
|
||||
(let [lengths (for list [indentation1 indentation2] (for line list line.length))
|
||||
deltaLists (for list lengths ~(for [from to] (pairs list) (- to from)))
|
||||
:Array<Array<Int>> zipped (apply zip deltaLists)]
|
||||
(doFor [a b] zipped
|
||||
(unless (= a b)
|
||||
(return null)))
|
||||
(apply min (second lengths))))
|
||||
|
||||
@(:expose "activate")
|
||||
(function activate [:ExtensionContext context]
|
||||
(printThroughInfoMessage)
|
||||
// Add your extension's commands here with (defCommand <...>):
|
||||
// (defCommand context yourExt.exampleCommand "An example command for your extension" "C-; C-1" [] (doSomething))
|
||||
(defCommand context startEditingSelection "Edit the currently selected text wherever it occurs in your workspace" "C-; C-d" []
|
||||
(assert activeTextEditor)
|
||||
(assert activeTextEditor.selection)
|
||||
(assert Vscode.workspace.workspaceFolders)
|
||||
(let [start (activeTextEditor.selection.start.with (object line null character 0))
|
||||
end (.with (activeTextEditor.selection.end.translate (object lineDelta 1 characterDelta null)) (object line null character 0))
|
||||
:String originalText (activeTextEditor.document.getText (new Range start end))
|
||||
originalLines (originalText.split "\n")
|
||||
_empty (originalLines.pop)
|
||||
ltrimmedLines (for line originalLines (line.ltrim))
|
||||
originalIndentation (for [original ltrimmed] (zip originalLines ltrimmedLines) (original.substr 0 (- original.length ltrimmed.length)))
|
||||
// Contains [file indentation index firstLine]
|
||||
:Array<Array<Dynamic>> placesToEdit []]
|
||||
(doFor folder Vscode.workspace.workspaceFolders
|
||||
(walkDirectory "" folder.uri.fsPath
|
||||
->file
|
||||
(let [lines (.split (sys.io.File.getContent file) "\n")
|
||||
enumeratedLines (enumerate lines)
|
||||
linesMatchingFirstLine
|
||||
(filter enumeratedLines
|
||||
(matchesLine (first ltrimmedLines)))]
|
||||
(localFunction matchesBlock [:Array<Dynamic> firstLineAndIndex]
|
||||
(let [indentation []
|
||||
linesToCheck (enumerate (lines.slice (first firstLineAndIndex) (+ (first firstLineAndIndex) originalLines.length)))]
|
||||
(unless (= linesToCheck.length originalLines.length)
|
||||
(return null))
|
||||
(doFor [index :String line] linesToCheck
|
||||
(unless ((matchesLine (nth ltrimmedLines index)) (nth linesToCheck index))
|
||||
(return null))
|
||||
(indentation.push (line.substr 0 (- line.length .length (line.ltrim)))))
|
||||
indentation))
|
||||
(doFor lineAndIndex linesMatchingFirstLine
|
||||
(whenLet [indentation (matchesBlock lineAndIndex)]
|
||||
(lineAndIndex.unshift indentation)
|
||||
(lineAndIndex.unshift file)
|
||||
(placesToEdit.push lineAndIndex))))
|
||||
->folder (case (haxe.io.Path.withoutDirectory folder)
|
||||
((or "node_modules" "bin") true) // Don't recurse into node_modules or generated files
|
||||
// TODO make a list of folders to ignore part of extension configuration
|
||||
(otherwise false))))
|
||||
(if placesToEdit
|
||||
{
|
||||
(doFor place placesToEdit
|
||||
(assert (indentationDeltasMatch originalIndentation (second place))))
|
||||
(print "Editing this text in ${placesToEdit.length} places.")
|
||||
(awaitLet [editedText (inputEditor "duplicateEditor.$(haxe.io.Path.extension activeTextEditor.document.fileName)" "Apply your edits" originalText)
|
||||
&sync editedLines (editedText.split "\n")
|
||||
&sync editedLtrimmedLines (for line editedLines (line.ltrim))
|
||||
&sync editedIndentation (for [edited ltrimmed] (zip editedLines editedLtrimmedLines) (edited.substr 0 (- edited.length ltrimmed.length)))
|
||||
&sync indentationChar (->{(doFor :String whitespace editedIndentation (when whitespace (return (whitespace.charAt 0)))) ""})
|
||||
&sync originalMinIndentation (apply min (for line originalIndentation line.length))
|
||||
&sync editedMinIndentation (apply min (for line editedIndentation line.length))]
|
||||
// Reverse placesToEdit so we edit files from end to start, preserving line number validity
|
||||
(doFor [file indentation blockLineNumber line] (reverse placesToEdit)
|
||||
(let [minIndentation (indentationDeltasMatch originalIndentation indentation)
|
||||
fileLines (.split (sys.io.File.getContent file) "\n")]
|
||||
// TODO do this by opening all the files and using reversible edit operations
|
||||
(fileLines.splice blockLineNumber originalLines.length)
|
||||
(doFor [index line] (enumerate editedLtrimmedLines)
|
||||
(fileLines.insert (+ blockLineNumber index) "$(* minIndentation indentationChar)$(* (- .length (nth editedIndentation index) editedMinIndentation) indentationChar)${line}"))
|
||||
(sys.io.File.saveContent file (fileLines.join "\n")))))
|
||||
null
|
||||
}
|
||||
(print "The selected text is not duplicated anywhere in your workspace folders (unless you are filtering it by accident!)."))
|
||||
))
|
||||
// Add your extension's configuration here with (defConfiguration <...>):
|
||||
// (defConfiguration
|
||||
// :Bool configBool
|
||||
// (object
|
||||
// default false)
|
||||
// :String configString
|
||||
// (object
|
||||
// default ""))
|
||||
)
|
3
projects/duplicate-text-editor/test.sh
Normal file
3
projects/duplicate-text-editor/test.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#! /bin/bash
|
||||
|
||||
haxe build.hxml
|
4
projects/duplicate-text-editor/test/file.txt
Normal file
4
projects/duplicate-text-editor/test/file.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
Contains duplicated text.
|
||||
A block of duplicated text.
|
||||
Containing 3 separate lines.
|
||||
|
11
projects/duplicate-text-editor/test/file2.txt
Normal file
11
projects/duplicate-text-editor/test/file2.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Contains duplicated text.
|
||||
A block of duplicated text.
|
||||
Containing 3 separate lines.
|
||||
|
||||
|
||||
|
||||
Contains duplicated text.
|
||||
A block of duplicated text.
|
||||
Containing 3 separate lines.
|
||||
|
||||
|
Reference in New Issue
Block a user