Skip to content

Commit

Permalink
Implemented diff algorithm for ropes and added basic formatter integr…
Browse files Browse the repository at this point in the history
…ation
  • Loading branch information
Nimaoth committed Dec 15, 2024
1 parent f6459cb commit c68b32d
Show file tree
Hide file tree
Showing 6 changed files with 654 additions and 7 deletions.
7 changes: 7 additions & 0 deletions config/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
},
"nim": {
"treesitter": "alaviss/tree-sitter-nim",
"formatter": "nph",
"tabWidth": 2,
"indent": "spaces",
"indentAfter": [
Expand Down Expand Up @@ -528,6 +529,12 @@
"maxViews": 2
},

"text": {
"reload-diff": true,
"reload-diff-timeout": 250,
"format-on-save": false,
},

"debugger": {
"type": {
"lldb-dap": {
Expand Down
53 changes: 53 additions & 0 deletions config/settings.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,30 @@
"type": "string",
"description": "Subdirectory of the repository which contains the queries. By default the queries are found by searching for highlights.scm"
},
"formatter": {
"oneOf": [
{
"type": "string",
"description": "Path of the formatter executable"
},
{
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Path of the formatter executable"
},
"args": {
"type": "array",
"items": {
"type": "string"
},
"description": "Arguments passed to the formatter"
}
}
}
],
},
"tabWidth": {
"type": "integer"
},
Expand Down Expand Up @@ -207,6 +231,35 @@
"additionalProperties": false
},

"^\\+?text$": {
"type": "object",
"properties": {
"reload-diff": {
"type": "boolean",
"description": "When set then the editor will, when reloading a file, calculate the diff between the content on disk and in memory, and apply the diff to update the in memory representation match the on disk representation.\nThis will reduce memory usage over time, but increase memory usage quite a bit while diffing.\nThe diffing has a timeout of 'text.reload-diff-timeout'. When this timeout is reached then diffing will be aborted and the file content will be loaded normally."
},
"reload-diff-timeout": {
"type": "integer",
"description": "Timeout in milliseconds for diffing when reloading files from disk."
},
"format-on-save": {
"type": "boolean",
"description": "When set the editor will run the specified formatter when saving. See 'languages.*.formatter'"
},
"^\\+?whitespace$": {
"type": "object",
"properties": {
"char": {
"type": "string"
}
}
},
"highlight-treesitter-errors": {
"type": "boolean"
}
}
},

"^\\+?editor$": {
"type": "object",
"properties": {
Expand Down
58 changes: 57 additions & 1 deletion src/misc/rope_utils.nim
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import std/[options, strutils]
import std/[options, strutils, atomics]
import nimsumtree/[rope, sumtree]
import scripting_api except DocumentEditor, TextDocumentEditor, AstDocumentEditor
from scripting_api as api import nil
import custom_async, custom_unicode, util
import text/diff

{.push gcsafe.}
{.push raises: [].}
Expand Down Expand Up @@ -38,6 +39,61 @@ proc createRopeAsync*(str: ptr string, rope: ptr Rope): Future[Option[int]] {.as
return errorIndex.some
return int.none

type DiffRopesData = object
rc: Atomic[int]
a: Rope
b: Rope
diff: ptr RopeDiff[int]
cancel: Atomic[bool]
threadDone: Atomic[bool]

proc diffRopeThread(data: ptr DiffRopesData) =
defer:
if data[].rc.fetchSub(1, moRelease) == 1:
fence(moAcquire)
try:
`=destroy`(data[])
`=wasMoved`(data[])
except:
discard
freeShared(data)

discard data[].rc.fetchAdd(1, moRelaxed)

var a = data.a.clone()
var b = data.b.clone()
var d = diff(a, b, data.cancel.addr)
if not data.cancel.load:
data.diff[] = d.ensureMove
data.threadDone.store(true)

proc diffRopeAsync*(a, b: sink Rope, res: ptr RopeDiff[int]): Future[void] {.async.} =
## Returns `some(index)` if the string contains invalid utf8 at `index`
let data = createShared(DiffRopesData)
data.rc.store(1)
data.a = a.clone()
data.b = b.clone()
data.diff = res
data.cancel.store(false)
data.threadDone.store(false)

defer:
if data[].rc.fetchSub(1, moRelease) == 1:
fence(moAcquire)
try:
{.gcsafe.}:
`=destroy`(data[])
`=wasMoved`(data[])
except:
discard
freeShared(data)

try:
await spawnAsync(diffRopeThread, data)
except CancelledError as e:
data.cancel.store(true)
raise e

######################################################################### Rope api only, maybe move to rope library later

func toCharsInLine*[D](self: Rope, position: D): Count =
Expand Down
Loading

0 comments on commit c68b32d

Please sign in to comment.