Skip to content

Commit

Permalink
A bunch of fixes, perf improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Nimaoth committed Sep 22, 2024
1 parent 3ed5e61 commit 64f94c8
Show file tree
Hide file tree
Showing 16 changed files with 380 additions and 189 deletions.
Binary file modified config/wasm/harpoon.wasm
Binary file not shown.
Binary file modified config/wasm/keybindings_plugin.wasm
Binary file not shown.
Binary file modified config/wasm/vscode_config_plugin.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion nev.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ requires "https://github.com/Nimaoth/boxy >= 0.4.2"
requires "https://github.com/Nimaoth/nimscripter >= 1.0.21"
requires "https://github.com/Nimaoth/nimtreesitter-api >= 0.1.15"
requires "https://github.com/Nimaoth/nimwasmtime >= 0.1.7"
requires "https://github.com/Nimaoth/nimsumtree >= 0.3.1"
requires "https://github.com/Nimaoth/nimsumtree >= 0.3.2"

# Use this to include all treesitter languages (takes longer to download)
requires "https://github.com/Nimaoth/nimtreesitter >= 0.1.6"
Expand Down
6 changes: 3 additions & 3 deletions nimble.lock
Original file line number Diff line number Diff line change
Expand Up @@ -272,13 +272,13 @@
}
},
"nimsumtree": {
"version": "0.3.1",
"vcsRevision": "3c03f938668a57ed568944116aceecacc24f24be",
"version": "0.3.2",
"vcsRevision": "349de4e24a8eae25b2e524fe85c9c75f18d6c2f6",
"url": "https://github.com/Nimaoth/nimsumtree",
"downloadMethod": "git",
"dependencies": [],
"checksums": {
"sha1": "c4c9d1f4116afdfdb5fbfea06302d79e7ae957d6"
"sha1": "dcc73e58286e2b4dcbf3a7038fbac52c5574f972"
}
},
"nimtreesitter": {
Expand Down
6 changes: 3 additions & 3 deletions scripting/editor_text_api_wasm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1433,7 +1433,7 @@ proc copy*(self: TextDocumentEditor; register: string = "";

proc editor_text_paste_void_TextDocumentEditor_string_bool_wasm(arg: cstring): cstring {.
importc.}
proc paste*(self: TextDocumentEditor; register: string = "";
proc paste*(self: TextDocumentEditor; registerName: string = "";
inclusiveEnd: bool = false) =
var argsJson = newJArray()
argsJson.add block:
Expand All @@ -1443,9 +1443,9 @@ proc paste*(self: TextDocumentEditor; register: string = "";
self.toJson()
argsJson.add block:
when string is JsonNode:
register
registerName
else:
register.toJson()
registerName.toJson()
argsJson.add block:
when bool is JsonNode:
inclusiveEnd
Expand Down
47 changes: 27 additions & 20 deletions src/app.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import platform/[platform, filesystem]
import workspaces/[workspace]
import config_provider, app_interface
import text/language/language_server_base, language_server_command_line
import input, events, document, document_editor, popup, dispatch_tables, theme, clipboard, app_options, selector_popup_builder, view, command_info
import input, events, document, document_editor, popup, dispatch_tables, theme, clipboard, app_options, selector_popup_builder, view, command_info, register
import text/[custom_treesitter]
import finder/[finder, previewer]
import compilation_config, vfs
Expand Down Expand Up @@ -118,16 +118,6 @@ type EditorState = object
debuggerState: Option[JsonNode]
sessionData: JsonNode

type
RegisterKind* {.pure.} = enum Text, AstNode
Register* = object
case kind*: RegisterKind
of RegisterKind.Text:
text*: string
of RegisterKind.AstNode:
when enableAst:
node*: AstNode

type ScriptAction = object
name: string
scriptContext: ScriptContext
Expand Down Expand Up @@ -261,6 +251,8 @@ proc handleLog(self: App, level: Level, args: openArray[string])
proc getEventHandlerConfig*(self: App, context: string): EventHandlerConfig
proc setRegisterTextAsync*(self: App, text: string, register: string = ""): Future[void] {.async.}
proc getRegisterTextAsync*(self: App, register: string = ""): Future[string] {.async.}
proc setRegisterAsync*(self: App, register: string, value: sink Register): Future[void]
proc getRegisterAsync*(self: App, register: string, res: ptr Register): Future[bool]
proc recordCommand*(self: App, command: string, args: string)
proc openWorkspaceFile*(self: App, path: string, append: bool = false): Option[DocumentEditor]
proc openFile*(self: App, path: string, appFile: bool = false): Option[DocumentEditor]
Expand Down Expand Up @@ -299,6 +291,8 @@ implTrait AppInterface, App:

setRegisterTextAsync(Future[void], App, string, string)
getRegisterTextAsync(Future[string], App, string)
setRegisterAsync(Future[void], App, string, sink Register)
getRegisterAsync(Future[bool], App, string, ptr Register)
recordCommand(void, App, string, string)

proc configProvider*(self: App): ConfigProvider = self.asConfigProvider
Expand Down Expand Up @@ -419,14 +413,6 @@ proc invokeAnyCallback*(self: App, context: string, args: JsonNode): JsonNode =
log(lvlError, getCurrentException().getStackTrace())
return nil

proc getText(register: var Register): string =
case register.kind
of RegisterKind.Text:
return register.text
of RegisterKind.AstNode:
assert false
return ""

method layoutViews*(layout: Layout, props: LayoutProperties, bounds: Rect, views: int): seq[Rect] {.base.} =
return @[bounds]

Expand Down Expand Up @@ -4077,6 +4063,27 @@ proc getRegisterTextAsync*(self: App, register: string = ""): Future[string] {.a

return ""

proc setRegisterAsync*(self: App, register: string, value: sink Register): Future[void] {.async.} =
if register.len == 0:
setSystemClipboardText(value.getText())
self.registers[register] = value.move

proc getRegisterAsync*(self: App, register: string, res: ptr Register): Future[bool] {.async.} =
if register.len == 0:
var text = getSystemClipboardText().await
if text.isSome:
if text.get.len > 1024:
res[] = Register(kind: Rope, rope: Rope.new(text.get.move))
else:
res[] = Register(kind: Text, text: text.get.move)
return true

if self.registers.contains(register):
res[] = self.registers[register].clone()
return true

return false

proc setRegisterText*(self: App, text: string, register: string = "") {.expose("editor").} =
self.registers[register] = Register(kind: RegisterKind.Text, text: text)

Expand Down Expand Up @@ -4159,7 +4166,7 @@ proc printStatistics*(self: App) {.expose("editor").} =
result.add &"Backend: {self.backend}\n"

result.add &"Registers:\n"
for (key, value) in self.registers.pairs:
for (key, value) in self.registers.mpairs:
result.add &" {key}: {value}\n"

result.add &"RecordingKeys:\n"
Expand Down
4 changes: 3 additions & 1 deletion src/app_interface.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import std/[json, options]
import misc/[traits, custom_async]
import platform/platform
import finder/[finder, previewer]
import events, popup, document_editor, document, config_provider, selector_popup_builder
import events, popup, document_editor, document, config_provider, selector_popup_builder, register
from scripting_api import EditorId

traitRef AppInterface:
Expand All @@ -11,6 +11,8 @@ traitRef AppInterface:
method getEventHandlerConfig*(self: AppInterface, context: string): EventHandlerConfig
method setRegisterTextAsync*(self: AppInterface, text: string, register: string): Future[void]
method getRegisterTextAsync*(self: AppInterface, register: string): Future[string]
method setRegisterAsync*(self: AppInterface, register: string, value: sink Register): Future[void]
method getRegisterAsync*(self: AppInterface, register: string, res: ptr Register): Future[bool]
method recordCommand*(self: AppInterface, command: string, args: string)
method openWorkspaceFile*(self: AppInterface, path: string, append: bool = false): Option[DocumentEditor]
method openFile*(self: AppInterface, path: string): Option[DocumentEditor]
Expand Down
22 changes: 11 additions & 11 deletions src/collab.nim
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ proc connectCollaboratorAsync(port: int) {.async.} =
let opsJson = parts[i..^1]
let content = await server.recv(length)

let ops = opsJson.parseJson.jsonTo(seq[Operation]).catch:
var ops = opsJson.parseJson.jsonTo(seq[Operation]).catch:
log lvlError, &"[collab][open {file}] Failed to parse operations: {getCurrentExceptionMsg()}\nops: {opsJson}\n{getCurrentException().getStackTrace()}"
continue

Expand All @@ -85,23 +85,23 @@ proc connectCollaboratorAsync(port: int) {.async.} =
let doc = doc.TextDocument
docs[file] = doc
doc.rebuildBuffer(1.ReplicaId, bufferId, content)
doc.applyRemoteChanges(ops)
doc.applyRemoteChanges(ops.move)

discard doc.onOperation.subscribe proc(arg: tuple[document: TextDocument, op: Operation]) =
opsToSend.add (arg.document.filename, arg.op)
opsToSend.add (arg.document.filename, arg.op.clone())
sendOpsTask.schedule()
else:
log lvlError, &"[collab-client] Document not found: '{file}', message: '{line}'"

elif line.startsWith("op "):
let file = line[3..^1]
let encoded = await server.recvLine()
let op = encoded.parseJson().jsonTo(Operation).catch:
var op = encoded.parseJson().jsonTo(Operation).catch:
log lvlError, &"Failed to parse operation: '{line}'"
continue

if app.getOrOpenDocument(file).getSome(doc) and doc of TextDocument:
doc.TextDocument.applyRemoteChanges(@[op])
doc.TextDocument.applyRemoteChanges(@[op.move])

else:
log lvlError, &"[collab-client] Unknown command '{line}'"
Expand Down Expand Up @@ -131,9 +131,9 @@ proc processCollabClient(client: AsyncSocket) {.async.} =
let doc = doc.TextDocument
if doc.filename != "" and doc.filename != "log":
let content = $doc.buffer.history.baseText
var allOps = collect:
for op in doc.buffer.history.operations.values:
op
var allOps = newSeqOfCap[Operation](doc.buffer.history.operations.len)
for op in doc.buffer.history.operations.mvalues:
allOps.add(op.clone())

allOps.sort((a, b) => cmp(a.timestamp, b.timestamp))

Expand All @@ -142,7 +142,7 @@ proc processCollabClient(client: AsyncSocket) {.async.} =
await client.send(content)

discard doc.onOperation.subscribe proc(arg: tuple[document: TextDocument, op: Operation]) =
opsToSend.add (arg.document.filename, arg.op)
opsToSend.add (arg.document.filename, arg.op.clone())
sendOpsTask.schedule()

while not client.isClosed:
Expand All @@ -153,12 +153,12 @@ proc processCollabClient(client: AsyncSocket) {.async.} =
if line.startsWith("op "):
let file = line[3..^1]
let encoded = await client.recvLine()
let op = encoded.parseJson().jsonTo(Operation).catch:
var op = encoded.parseJson().jsonTo(Operation).catch:
log lvlError, &"[collab-server] Failed to parse operation: '{line}'"
continue

if app.getOrOpenDocument(file).getSome(doc) and doc of TextDocument:
doc.TextDocument.applyRemoteChanges(@[op])
doc.TextDocument.applyRemoteChanges(@[op.move])

else:
log lvlError, &"[collab-server] Unknown command '{line}'"
Expand Down
17 changes: 16 additions & 1 deletion src/finder/workspace_file_previewer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import finder, previewer
import vcs/vcs
import app_interface, config_provider, vfs

import nimsumtree/[rope]

logCategory "workspace-file-previewer"

type
Expand Down Expand Up @@ -156,8 +158,21 @@ proc loadAsync(self: WorkspaceFilePreviewer): Future[void] {.async.} =
log lvlInfo, fmt"Discard file load of '{path}' because a newer one was requested"
return

var rope: Rope
if createRopeAsync(content.move, rope.addr).await.getSome(errorIndex):
rope = Rope.new(&"Invalid utf-8 byte at {errorIndex}")
return

if editor.document.isNil:
log lvlInfo, fmt"Discard file load of '{path}' because preview editor was destroyed"
return

if self.revision > revision or editor.document.isNil:
log lvlInfo, fmt"Discard file load of '{path}' because a newer one was requested"
return

self.tempDocument.workspace = self.workspace.some
self.tempDocument.setFileAndContent(path, content.move)
self.tempDocument.setFileAndContent(path, rope.move)
editor.setDocument(self.tempDocument)

if location.getSome(location):
Expand Down
8 changes: 7 additions & 1 deletion src/misc/util.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export options
{.used.}

template getSome*[T](opt: Option[T], injected: untyped): bool =
((let o = opt; o.isSome())) and ((let injected {.inject.} = o.get(); true))
((let o = opt; o.isSome())) and ((let injected {.inject, cursor.} = o.get(); true))

template isNotNil*(v: untyped): untyped = not v.isNil

Expand Down Expand Up @@ -32,6 +32,12 @@ template take*[T](opt: sink Option[T], otherwise: sink T): T =
else:
otherwise

template take*[T](opt: sink Option[T]): T =
if opt.isSome:
opt.get.move
else:
raise newException(UnpackDefect, "Can't obtain a value from a `none`")

func get*[T](opt: openArray[T], index: int): Option[T] =
if index in 0..opt.high:
opt[index].some
Expand Down
30 changes: 30 additions & 0 deletions src/register.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import std/strutils
import nimsumtree/rope

type
RegisterKind* {.pure.} = enum Text, Rope
Register* = object
case kind*: RegisterKind
of RegisterKind.Text:
text*: string
of RegisterKind.Rope:
rope*: Rope

func clone*(register: Register): Register =
case register.kind
of Text: Register(kind: Text, text: register.text)
of Rope: Register(kind: Rope, rope: register.rope.clone())

proc getText*(register: Register): string =
case register.kind
of RegisterKind.Text:
return register.text
of RegisterKind.Rope:
return $register.rope

proc numLines*(register: Register): int =
case register.kind
of RegisterKind.Text:
return register.text.count('\n') + 1
of RegisterKind.Rope:
return register.rope.lines
Loading

0 comments on commit 64f94c8

Please sign in to comment.