separate ktxt2 parsing logic from VScode API
This commit is contained in:
@@ -1,107 +0,0 @@
|
||||
// Kiss-VSCode command functions for authoring ktxt2 files.
|
||||
// ktxt2 files contain an original "SOURCE" file and a translated "OUTPUT" file
|
||||
// which is authored semi-automatically with the help of these commands.
|
||||
// A file called README.md.html.ktxt2 would be for converting README.md to README.html.
|
||||
|
||||
(var blockStartEnd "|||")
|
||||
(var unlockedStart "|>|")
|
||||
(var lockedStart "|!|")
|
||||
(var outputStarts [unlockedStart lockedStart])
|
||||
|
||||
// Return [sourceFile outputFile]
|
||||
(function :Array<String> splitFileContents []
|
||||
(let [fileText (activeTextEditor.document.getText)
|
||||
fileStream (kiss.Stream.fromString fileText)
|
||||
&mut sourceText ""
|
||||
&mut outputText ""]
|
||||
(loop
|
||||
(case (fileStream.takeUntilAndDrop blockStartEnd)
|
||||
((Some _)
|
||||
(let [sourceBlock (fileStream.expect "A chunk of source text followed by one of $outputStarts"
|
||||
->(fileStream.takeUntilOneOf outputStarts))]
|
||||
(+= sourceText "${sourceBlock}\n"))
|
||||
(assert (apply = (for outputStart outputStarts outputStart.length)) "all output starts must be the same length!")
|
||||
(fileStream.dropChars .length (first outputStarts))
|
||||
(let [outputBlock (fileStream.expect "A chunk of output text followed by $blockStartEnd"
|
||||
->(fileStream.takeUntilAndDrop blockStartEnd))]
|
||||
(+= outputText "${outputBlock}\n")))
|
||||
(None
|
||||
(break))))
|
||||
[sourceText outputText]))
|
||||
|
||||
(function exportKtxt2Files [&opt _]
|
||||
(let [[sourceText outputText] (splitFileContents)
|
||||
ktxt2FullFilename activeTextEditor.document.fileName
|
||||
ktxt2Directory (haxe.io.Path.directory ktxt2FullFilename)
|
||||
ktxt2Filename (haxe.io.Path.withoutDirectory ktxt2FullFilename)
|
||||
[baseFilename sourceExt outputExt ktxt2Ext] (ktxt2Filename.split ".")
|
||||
sourceFilename (joinPath ktxt2Directory "${baseFilename}.${sourceExt}")
|
||||
outputFilename (joinPath ktxt2Directory "${baseFilename}.${outputExt}")]
|
||||
// Use editors instead of File.saveContent for this, so the user can undo the export if
|
||||
// it overwrites something!
|
||||
(defMacro overwriteDocument [document content]
|
||||
`(let [document ,document content ,content]
|
||||
(awaitLet [editor (Vscode.window.showTextDocument document)]
|
||||
(editor.edit
|
||||
->e (e.replace (new Range (document.positionAt 0) (document.positionAt .length (document.getText))) content)))))
|
||||
(function uriFor [filename]
|
||||
(let [uri (Uri.file filename)]
|
||||
(if (sys.FileSystem.exists filename)
|
||||
uri
|
||||
(uri.with (object scheme "untitled")))))
|
||||
(awaitLet [sourceDocument
|
||||
(Vscode.workspace.openTextDocument (uriFor sourceFilename))
|
||||
sourceEditSuccess
|
||||
(overwriteDocument sourceDocument sourceText)
|
||||
outputDocument
|
||||
(Vscode.workspace.openTextDocument (uriFor outputFilename))
|
||||
outputEditSuccess
|
||||
(overwriteDocument outputDocument outputText)]
|
||||
(assert (and sourceEditSuccess outputEditSuccess))
|
||||
(awaitLet [saveSourceSuccess
|
||||
(sourceDocument.save)
|
||||
saveOutputSuccess
|
||||
(outputDocument.save)]
|
||||
(assert (and saveSourceSuccess saveOutputSuccess))))))
|
||||
|
||||
(function streamPosToVscodePos [pos]
|
||||
(new vscode.Position pos.line (- pos.column 1)))
|
||||
|
||||
(function rangeFromStartEnd [start end]
|
||||
(new Range (streamPosToVscodePos start) (streamPosToVscodePos end)))
|
||||
|
||||
(function :Array<Dynamic> splitFileBlocks []
|
||||
(let [fileText (activeTextEditor.document.getText)
|
||||
fileStream (kiss.Stream.fromString fileText)
|
||||
blocks []]
|
||||
(loop
|
||||
(let [block (object source "" sourceRange null output "" outputRange null outputLocked false)]
|
||||
(case (fileStream.takeUntilAndDrop blockStartEnd)
|
||||
((Some _)
|
||||
(let [sourceStartPosition (fileStream.position)
|
||||
sourceBlock (fileStream.expect "A chunk of source text followed by one of $outputStarts"
|
||||
->(fileStream.takeUntilOneOf outputStarts))
|
||||
sourceEndPosition (fileStream.position)]
|
||||
(set block.source sourceBlock)
|
||||
(set block.sourceRange (rangeFromStartEnd sourceStartPosition sourceEndPosition)))
|
||||
(assert (apply = (for outputStart outputStarts outputStart.length)) "all output starts must be the same length!")
|
||||
(set block.outputLocked
|
||||
(case (fileStream.expect "One of $outputStarts" ->(fileStream.takeChars .length (first outputStarts)))
|
||||
(lockedStart true)
|
||||
(unlockedStart false)
|
||||
(otherwise
|
||||
(throw "Expected one of $outputStarts"))))
|
||||
(let [outputStartPosition (fileStream.position)
|
||||
outputBlock (fileStream.expect "A chunk of output text followed by $blockStartEnd"
|
||||
->(fileStream.takeUntilOneOf [blockStartEnd]))
|
||||
outputEndPosition (fileStream.position)]
|
||||
(fileStream.dropChars blockStartEnd.length)
|
||||
(set block.output outputBlock)
|
||||
(set block.outputRange (rangeFromStartEnd outputStartPosition outputEndPosition))))
|
||||
(None
|
||||
(break)))
|
||||
(blocks.push block)))
|
||||
blocks))
|
||||
|
||||
(function splitBlocks [&opt _]
|
||||
(let [blocks (splitFileBlocks)] (print blocks)))
|
23
projects/kiss-vscode/src/ktxt2/KTxt2.hx
Normal file
23
projects/kiss-vscode/src/ktxt2/KTxt2.hx
Normal file
@@ -0,0 +1,23 @@
|
||||
package ktxt2;
|
||||
|
||||
import kiss.Stream;
|
||||
import kiss.Prelude;
|
||||
|
||||
typedef KTxt2Block = {
|
||||
source:String,
|
||||
output:String,
|
||||
outputLocked:Bool,
|
||||
// kiss.Stream.Positions:
|
||||
sourceStart:Position,
|
||||
sourceEnd:Position,
|
||||
outputStart:Position,
|
||||
outputEnd:Position
|
||||
};
|
||||
|
||||
enum KTxt2Element {
|
||||
Comment(content:String);
|
||||
Block(block:KTxt2Block);
|
||||
}
|
||||
|
||||
@:build(kiss.Kiss.build())
|
||||
class KTxt2 {}
|
76
projects/kiss-vscode/src/ktxt2/KTxt2.kiss
Normal file
76
projects/kiss-vscode/src/ktxt2/KTxt2.kiss
Normal file
@@ -0,0 +1,76 @@
|
||||
// Functions for parsing and modifying ktxt2 files.
|
||||
|
||||
// ktxt2 files contain an original "SOURCE" file and a translated "OUTPUT" file
|
||||
// which is authored semi-automatically with the help of a custom VSCode editor.
|
||||
// A file called README.md.html.ktxt2 would be for converting README.md -> README.html.
|
||||
|
||||
(var blockStartEnd "|||")
|
||||
(var unlockedStart "|>|")
|
||||
(var lockedStart "|!|")
|
||||
(var outputStarts [unlockedStart lockedStart])
|
||||
|
||||
// Return [sourceFile outputFile]
|
||||
(function :Array<String> splitFileContents [file]
|
||||
(let [fileStream (kiss.Stream.fromFile file)
|
||||
&mut sourceText ""
|
||||
&mut outputText ""]
|
||||
(loop
|
||||
(case (fileStream.takeUntilAndDrop blockStartEnd)
|
||||
((Some _)
|
||||
(let [sourceBlock (fileStream.expect "A chunk of source text followed by one of $outputStarts"
|
||||
->(fileStream.takeUntilOneOf outputStarts))]
|
||||
(+= sourceText "${sourceBlock}\n"))
|
||||
(assert (apply = (for outputStart outputStarts outputStart.length)) "all output starts must be the same length!")
|
||||
(fileStream.dropChars .length (first outputStarts))
|
||||
(let [outputBlock (fileStream.expect "A chunk of output text followed by $blockStartEnd"
|
||||
->(fileStream.takeUntilAndDrop blockStartEnd))]
|
||||
(+= outputText "${outputBlock}\n")))
|
||||
(None
|
||||
(break))))
|
||||
[sourceText outputText]))
|
||||
|
||||
(function :Array<KTxt2Element> splitFileElements [file]
|
||||
(let [fileStream (kiss.Stream.fromFile file)
|
||||
elements []]
|
||||
(loop
|
||||
(let [block
|
||||
(object
|
||||
source ""
|
||||
sourceStart null
|
||||
sourceEnd null
|
||||
output ""
|
||||
outputStart null
|
||||
outputEnd null
|
||||
outputLocked false)]
|
||||
// Look for the start of a KTxt2 block
|
||||
(case (fileStream.takeUntilAndDrop blockStartEnd)
|
||||
((Some comment)
|
||||
// Anything before the start of the block is a comment
|
||||
(when comment
|
||||
(elements.push (Comment comment)))
|
||||
(let [sourceStartPosition (fileStream.position)
|
||||
sourceBlock (fileStream.expect "A chunk of source text followed by one of $outputStarts"
|
||||
->(fileStream.takeUntilOneOf outputStarts))
|
||||
sourceEndPosition (fileStream.position)]
|
||||
(set block.source sourceBlock)
|
||||
(set block.sourceStart sourceStartPosition)
|
||||
(set block.sourceEnd sourceEndPosition))
|
||||
(assert (apply = (for outputStart outputStarts outputStart.length)) "all output starts must be the same length!")
|
||||
(set block.outputLocked
|
||||
(case (fileStream.expect "One of $outputStarts" ->(fileStream.takeChars .length (first outputStarts)))
|
||||
(lockedStart true)
|
||||
(unlockedStart false)
|
||||
(otherwise
|
||||
(throw "Expected one of $outputStarts"))))
|
||||
(let [outputStartPosition (fileStream.position)
|
||||
outputBlock (fileStream.expect "A chunk of output text followed by $blockStartEnd"
|
||||
->(fileStream.takeUntilOneOf [blockStartEnd]))
|
||||
outputEndPosition (fileStream.position)]
|
||||
(fileStream.dropChars blockStartEnd.length)
|
||||
(set block.output outputBlock)
|
||||
(set block.outputStart outputStartPosition)
|
||||
(set block.outputEnd outputEndPosition)))
|
||||
(None
|
||||
(break)))
|
||||
(elements.push (Block block))))
|
||||
elements))
|
@@ -1,5 +1,6 @@
|
||||
package ktxt2;
|
||||
|
||||
@:build(kiss.Kiss.build())
|
||||
class KTxt2Editor {
|
||||
public static function main() {
|
||||
var vscode = EditorExterns.acquireVsCodeApi();
|
||||
|
45
projects/kiss-vscode/src/ktxt2/KTxt2Editor.kiss
Normal file
45
projects/kiss-vscode/src/ktxt2/KTxt2Editor.kiss
Normal file
@@ -0,0 +1,45 @@
|
||||
(function exportSourceAndOutputFiles [document]
|
||||
(let [[sourceText outputText] (splitFileContents document.fileName)
|
||||
ktxt2FullFilename document.fileName
|
||||
ktxt2Directory (haxe.io.Path.directory ktxt2FullFilename)
|
||||
ktxt2Filename (haxe.io.Path.withoutDirectory ktxt2FullFilename)
|
||||
[baseFilename sourceExt outputExt ktxt2Ext] (ktxt2Filename.split ".")
|
||||
sourceFilename (joinPath ktxt2Directory "${baseFilename}.${sourceExt}")
|
||||
outputFilename (joinPath ktxt2Directory "${baseFilename}.${outputExt}")]
|
||||
// Use editors instead of File.saveContent for this, so the user can undo the export if
|
||||
// it overwrites something!
|
||||
(defMacro overwriteDocument [document content]
|
||||
`(let [document ,document content ,content]
|
||||
(awaitLet [editor (Vscode.window.showTextDocument document)]
|
||||
(editor.edit
|
||||
->e (e.replace (new Range (document.positionAt 0) (document.positionAt .length (document.getText))) content)))))
|
||||
(function uriFor [filename]
|
||||
(let [uri (Uri.file filename)]
|
||||
(if (sys.FileSystem.exists filename)
|
||||
uri
|
||||
(uri.with (object scheme "untitled")))))
|
||||
(awaitLet [sourceDocument
|
||||
(Vscode.workspace.openTextDocument (uriFor sourceFilename))
|
||||
sourceEditSuccess
|
||||
(overwriteDocument sourceDocument sourceText)
|
||||
outputDocument
|
||||
(Vscode.workspace.openTextDocument (uriFor outputFilename))
|
||||
outputEditSuccess
|
||||
(overwriteDocument outputDocument outputText)]
|
||||
(assert (and sourceEditSuccess outputEditSuccess))
|
||||
(awaitLet [saveSourceSuccess
|
||||
(sourceDocument.save)
|
||||
saveOutputSuccess
|
||||
(outputDocument.save)]
|
||||
(assert (and saveSourceSuccess saveOutputSuccess))))))
|
||||
|
||||
(function streamPosToVscodePos [pos]
|
||||
(new vscode.Position pos.line (- pos.column 1)))
|
||||
|
||||
(function rangeFromStartEnd [start end]
|
||||
(new Range (streamPosToVscodePos start) (streamPosToVscodePos end)))
|
||||
|
||||
|
||||
|
||||
(function splitBlocks [&opt _]
|
||||
(let [blocks (splitFileBlocks)] (print blocks)))
|
Reference in New Issue
Block a user