Skip to content

Commit

Permalink
mount local vfs under local://, fixed some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Nimaoth committed Oct 25, 2024
1 parent 661be06 commit ad83d2f
Show file tree
Hide file tree
Showing 13 changed files with 104 additions and 85 deletions.
6 changes: 2 additions & 4 deletions src/app.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1450,9 +1450,7 @@ proc browseKeybinds*(self: App, preview: bool = true, scaleX: float = 0.9, scale
if popup.getPreviewSelection().getSome(selection):
targetSelection = selection.some

let pathNorm = self.vfs.normalize(path)

let editor = self.layout.openFile(pathNorm)
let editor = self.layout.openFile(path)
if editor.getSome(editor) and editor of TextDocumentEditor and targetSelection.isSome:
editor.TextDocumentEditor.targetSelection = targetSelection.get
editor.TextDocumentEditor.centerCursor()
Expand Down Expand Up @@ -1839,7 +1837,7 @@ proc installTreesitterParserAsync*(self: App, language: string, host: string) {.
log lvlError, &"Invalid value for languages.{language}.treesitter: '{repo}'. Expected 'user/repo'"
return

let languagesRoot = self.vfs.normalize("app://languages")
let languagesRoot = self.vfs.localize("app://languages")
let userName = parts[0]
let repoName = parts[1]
let subFolder = parts[2..^1].join("/")
Expand Down
7 changes: 4 additions & 3 deletions src/document.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ method deinit*(self: Document) {.base, gcsafe, raises: [].} = discard
method getStatisticsString*(self: Document): string {.base, gcsafe, raises: [].} = discard

proc normalizedPath*(self: Document): string {.gcsafe, raises: [].} =
if self.vfs.isNotNil:
return self.vfs.normalize(self.filename)
return self.filename
return self.vfs.normalize(self.filename)

proc localizedPath*(self: Document): string {.gcsafe, raises: [].} =
return self.vfs.localize(self.filename)
4 changes: 2 additions & 2 deletions src/finder/workspace_file_previewer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ proc loadAsync(self: FilePreviewer): Future[void] {.async.} =
let location = self.currentLocation
let editor = self.editor

logScope lvlDebug, &"loadAsync '{path}'"
logScope lvlInfo, &"loadAsync '{path}'"

let document = if self.currentStaged or not self.reuseExistingDocuments:
Document.none
Expand Down Expand Up @@ -189,7 +189,7 @@ method previewItem*(self: FilePreviewer, item: FinderItem, editor: DocumentEdito
if not (editor of TextDocumentEditor):
return

logScope lvlDebug, &"previewItem {item}"
logScope lvlInfo, &"previewItem {item}"

inc self.revision
self.editor = editor.TextDocumentEditor
Expand Down
8 changes: 6 additions & 2 deletions src/layout.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import platform/platform
import misc/[custom_async, custom_logger, rect_utils, myjsonutils, util]
import scripting/expose
import workspaces/workspace
import service, platform_service, dispatch_tables, document, document_editor, view, events, config_provider, popup, selector_popup_builder
import service, platform_service, dispatch_tables, document, document_editor, view, events, config_provider, popup, selector_popup_builder, vfs, vfs_service
from scripting_api import EditorId

{.push gcsafe.}
Expand Down Expand Up @@ -33,6 +33,7 @@ type
workspace: Workspace
config: ConfigService
editors: DocumentEditorService
vfs: VFS
popups*: seq[Popup]
layout*: Layout
layoutProps*: LayoutProperties
Expand All @@ -54,14 +55,15 @@ var gPushSelectorPopupImpl*: PushSelectorPopupImpl

func serviceName*(_: typedesc[LayoutService]): string = "LayoutService"

addBuiltinService(LayoutService, PlatformService, ConfigService, DocumentEditorService, Workspace)
addBuiltinService(LayoutService, PlatformService, ConfigService, DocumentEditorService, Workspace, VFSService)

method init*(self: LayoutService): Future[Result[void, ref CatchableError]] {.async: (raises: []).} =
log lvlInfo, &"LayoutService.init"
self.platform = self.services.getService(PlatformService).get.platform
assert self.platform != nil
self.config = self.services.getService(ConfigService).get
self.editors = self.services.getService(DocumentEditorService).get
self.vfs = self.services.getService(VFSService).get.vfs
self.layout = HorizontalLayout()
self.layout_props = LayoutProperties(props: {"main-split": 0.5.float32}.toTable)
self.pushSelectorPopupImpl = ({.gcsafe.}: gPushSelectorPopupImpl)
Expand Down Expand Up @@ -444,6 +446,8 @@ proc openFile*(self: LayoutService, path: string, appFile: bool = false): Option
defer:
self.platform.requestRender()

let path = self.vfs.normalize(path)

log lvlInfo, fmt"[openFile] Open file '{path}' (appFile = {appFile})"
if self.tryOpenExisting(path, appFile, append = false).getSome(ed):
log lvlInfo, fmt"[openFile] found existing editor"
Expand Down
39 changes: 27 additions & 12 deletions src/platform/gui_platform.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import std/[tables, strutils, options, sets]
import std/[tables, strutils, options, sets, os]
import chroma, vmath, windy, boxy, boxy/textures, opengl, pixie/[contexts, fonts]
import misc/[custom_logger, util, event, id, rect_utils]
import misc/[custom_logger, util, event, id, rect_utils, custom_async]
import ui/node
import platform
import input, monitors, lrucache, theme, compilation_config, vfs
Expand Down Expand Up @@ -245,27 +245,42 @@ method requestRender*(self: GuiPlatform, redrawEverything = false) =
self.requestedRender = true
self.redrawEverything = self.redrawEverything or redrawEverything

proc readTypeface(vfs: VFS, filePath: string): Typeface {.raises: [IOError].} =
try:
result =
case splitFile(filePath).ext.toLowerAscii():
of ".ttf":
parseTtf(vfs.read(filePath, {Binary}).waitFor)
of ".otf":
parseOtf(vfs.read(filePath, {Binary}).waitFor)
of ".svg":
parseSvgFont(vfs.read(filePath, {Binary}).waitFor)
else:
raise newException(IOError, "Unsupported font format")
except Exception as e:
raise newException(IOError, &"Failed to load typeface '{filePath}': " & e.msg, e)

result.filePath = filePath

proc getTypeface*(self: GuiPlatform, font: string): Typeface =
if font notin self.typefaces:
var typeface: Typeface = nil
try:
let path = self.vfs.normalize(font)
log lvlInfo, &"Reading font '{path}'"
typeface = readTypeface(path)
log lvlInfo, &"Reading font '{font}'"
typeface = self.vfs.readTypeface(font)
self.typefaces[font] = typeface

for fallbackFont in self.fallbackFonts:
try:
let fallbackPath = self.vfs.normalize(fallbackFont)
log lvlInfo, &"Reading fallback font '{fallbackPath}'"
let fallback = readTypeface(fallbackPath)
log lvlInfo, &"Reading fallback font '{fallbackFont}'"
let fallback = self.vfs.readTypeface(fallbackFont)
if fallback.isNotNil:
typeface.fallbacks.add fallback
except:
log lvlError, &"Failed to load fallback font '{fallbackFont}'"
except IOError as e:
log lvlError, &"Failed to load fallback font '{fallbackFont}': {e.msg}"

except:
log lvlError, &"Failed to load font '{font}'"
except IOError as e:
log lvlError, &"Failed to load typeface '{font}': {e.msg}"
return nil

result = self.typefaces[font]
Expand Down
2 changes: 1 addition & 1 deletion src/scripting/scripting_wasm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ proc loadModules(self: ScriptContextWasm, path: string): Future[void] {.async.}
if not file2.endsWith(".wasm"):
continue

let file = self.vfs.normalize(path // file2)
let file = path // file2

try:
log lvlInfo, fmt"Try to load wasm module '{file}' from app directory"
Expand Down
2 changes: 1 addition & 1 deletion src/text/completion_provider_lsp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ proc getLspCompletionsAsync(self: CompletionProviderLsp) {.async.} =
await sleepAsync(2.milliseconds)

# debugf"[getLspCompletionsAsync] start"
let completions = await self.languageServer.getCompletions(self.document.normalizedPath, location)
let completions = await self.languageServer.getCompletions(self.document.localizedPath, location)
if completions.isSuccess:
log lvlInfo, fmt"[getLspCompletionsAsync] at {location}: got {completions.result.items.len} completions"
self.unfilteredCompletions = completions.result.items
Expand Down
51 changes: 31 additions & 20 deletions src/text/language/language_server_lsp.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import std/[strutils, options, json, tables, uri, strformat, sequtils, typedthreads]
import scripting_api except DocumentEditor, TextDocumentEditor, AstDocumentEditor
import misc/[event, util, custom_logger, custom_async, myjsonutils, custom_unicode, id, response, async_process]
import language_server_base, app_interface, config_provider, lsp_client, document, service, vfs
import language_server_base, app_interface, config_provider, lsp_client, document, service, vfs, vfs_service
import workspaces/workspace as ws

import nimsumtree/buffer
Expand All @@ -20,6 +20,9 @@ type LanguageServerLSP* = ref object of LanguageServer
serverCapabilities*: ServerCapabilities
fullDocumentSync: bool = false

vfs: VFS
localVfs: VFS

var languageServers = initTable[string, LanguageServerLSP]()

proc deinitLanguageServers*() =
Expand Down Expand Up @@ -108,7 +111,9 @@ proc getOrCreateLanguageServerLSP*(languageId: string, workspaces: seq[string],
return lsp.LanguageServer.some

{.gcsafe.}:
let configs = gServices.getService(ConfigService).get
let services = gServices

let configs = services.getService(ConfigService).get

let config = configs.getOption("lsp." & languageId, newJObject())
if config.isNil:
Expand Down Expand Up @@ -142,6 +147,8 @@ proc getOrCreateLanguageServerLSP*(languageId: string, workspaces: seq[string],
lsp.initializedFuture = newFuture[bool]("lsp.initializedFuture")
{.gcsafe.}:
languageServers[languageId] = lsp
lsp.vfs = services.getService(VFSService).get.vfs
lsp.localVfs = lsp.vfs.getVFS("local://").vfs # todo

asyncSpawn lsp.handleWorkspaceConfigurationRequests()
asyncSpawn lsp.handleMessages()
Expand Down Expand Up @@ -178,6 +185,10 @@ proc getOrCreateLanguageServerLSP*(languageId: string, workspaces: seq[string],
except:
return LanguageServer.none

proc toVfsPath(self: LanguageServerLSP, lspPath: string): string =
let localPath = lspPath.decodeUrl.parseUri.path.normalizePathUnix
return self.localVfs.normalize(localPath)

method start*(self: LanguageServerLSP): Future[void] = discard
method stop*(self: LanguageServerLSP) {.gcsafe, raises: [].} =
log lvlInfo, fmt"Stopping language server for '{self.languageId}'"
Expand All @@ -195,15 +206,15 @@ template locationsResponseToDefinitions(parsedResponse: untyped): untyped =
block:
if parsedResponse.asLocation().getSome(loc):
@[Definition(
filename: loc.uri.decodeUrl.parseUri.path.normalizePathUnix,
filename: self.toVfsPath(loc.uri),
location: (line: loc.`range`.start.line, column: loc.`range`.start.character)
)]

elif parsedResponse.asLocationSeq().getSome(locations) and locations.len > 0:
var res = newSeq[Definition]()
for location in locations:
res.add Definition(
filename: location.uri.decodeUrl.parseUri.path.normalizePathUnix,
filename: self.toVfsPath(location.uri),
location: (line: location.`range`.start.line, column: location.`range`.start.character)
)
res
Expand All @@ -212,7 +223,7 @@ template locationsResponseToDefinitions(parsedResponse: untyped): untyped =
var res = newSeq[Definition]()
for location in locations:
res.add Definition(
filename: location.targetUri.decodeUrl.parseUri.path.normalizePathUnix,
filename: self.toVfsPath(location.targetUri),
location: (
line: location.targetSelectionRange.start.line,
column: location.targetSelectionRange.start.character
Expand Down Expand Up @@ -312,7 +323,7 @@ method getReferences*(self: LanguageServerLSP, filename: string, location: Curso
var res = newSeq[Definition]()
for location in locations:
res.add Definition(
filename: location.uri.decodeUrl.parseUri.path.normalizePathUnix,
filename: self.toVfsPath(location.uri),
location: (line: location.`range`.start.line, column: location.`range`.start.character)
)
return res
Expand Down Expand Up @@ -455,15 +466,15 @@ method getSymbols*(self: LanguageServerLSP, filename: string): Future[seq[Symbol
location: (line: r.range.start.line, column: r.range.start.character),
name: r.name,
symbolType: r.kind.toInternalSymbolKind,
filename: filename,
filename: self.localVfs.normalize(filename),
)

for child in r.children:
completions.add Symbol(
location: (line: child.range.start.line, column: child.range.start.character),
name: child.name,
symbolType: child.kind.toInternalSymbolKind,
filename: filename,
filename: self.localVfs.normalize(filename),
)


Expand All @@ -475,7 +486,7 @@ method getSymbols*(self: LanguageServerLSP, filename: string): Future[seq[Symbol
location: (line: r.location.range.start.line, column: r.location.range.start.character),
name: r.name,
symbolType: symbolKind,
filename: r.location.uri.decodeUrl.parseUri.path.normalizePathUnix,
filename: self.toVfsPath(r.location.uri),
)

return completions
Expand All @@ -498,9 +509,9 @@ method getWorkspaceSymbols*(self: LanguageServerLSP, query: string): Future[seq[
for r in symbols:
let (path, location) = if r.location.asLocation().getSome(location):
let cursor = (line: location.range.start.line, column: location.range.start.character)
(location.uri.parseUri.path.decodeUrl.normalizePathUnix, cursor.some)
(self.toVfsPath(location.uri), cursor.some)
elif r.location.asUriObject().getSome(uri):
(uri.uri.parseUri.path.decodeUrl.normalizePathUnix, Cursor.none)
(self.toVfsPath(uri.uri), Cursor.none)
else:
log lvlError, fmt"Failed to parse workspace symbol location: {r.location}"
continue
Expand All @@ -522,7 +533,7 @@ method getWorkspaceSymbols*(self: LanguageServerLSP, query: string): Future[seq[
location: (line: r.location.range.start.line, column: r.location.range.start.character),
name: r.name,
symbolType: symbolKind,
filename: r.location.uri.parseUri.path.decodeUrl.normalizePathUnix,
filename: self.toVfsPath(r.location.uri),
)

else:
Expand Down Expand Up @@ -572,19 +583,19 @@ method connect*(self: LanguageServerLSP, document: Document) =
var handle = new Id
handle[] = document.onLoaded.subscribe proc(document: TextDocument): void =
document.onLoaded.unsubscribe handle[]
asyncSpawn self.client.notifyTextDocumentOpenedChannel.send (self.languageId, document.normalizedPath, document.contentString)
asyncSpawn self.client.notifyTextDocumentOpenedChannel.send (self.languageId, document.localizedPath, document.contentString)
else:
asyncSpawn self.client.notifyTextDocumentOpenedChannel.send (self.languageId, document.normalizedPath, document.contentString)
asyncSpawn self.client.notifyTextDocumentOpenedChannel.send (self.languageId, document.localizedPath, document.contentString)

let onEditHandle = document.onEdit.subscribe proc(args: auto): void {.gcsafe, raises: [].} =
# debugf"TEXT INSERTED {args.document.normalizedPath}:{args.location}: {args.text}"
# debugf"TEXT INSERTED {args.document.localizedPath}:{args.location}: {args.text}"
# todo: we should batch these, as onEdit can be called multiple times per frame
# especially for full document sync
let version = args.document.buffer.history.versions.high
let normalizedPath = args.document.normalizedPath
let localizedPath = args.document.localizedPath

if self.fullDocumentSync:
asyncSpawn self.client.notifyTextDocumentChangedChannel.send (normalizedPath, version, @[], args.document.contentString)
asyncSpawn self.client.notifyTextDocumentChangedChannel.send (localizedPath, version, @[], args.document.contentString)
else:
var c = args.document.buffer.visibleText.cursorT(Point)
# todo: currently relies on edits being sorted
Expand All @@ -593,7 +604,7 @@ method connect*(self: LanguageServerLSP, document: Document) =
let text = c.slice(Point.init(it.new.last.line, it.new.last.column))
TextDocumentContentChangeEvent(range: language_server_base.toLspRange(it.old), text: $text)
)
asyncSpawn self.client.notifyTextDocumentChangedChannel.send (normalizedPath, version, changes, "")
asyncSpawn self.client.notifyTextDocumentChangedChannel.send (localizedPath, version, changes, "")

self.documentHandles.add (document.Document, onEditHandle)

Expand All @@ -613,8 +624,8 @@ method disconnect*(self: LanguageServerLSP, document: Document) {.gcsafe, raises
self.documentHandles.removeSwap i
break

# asyncSpawn self.client.notifyClosedTextDocument(document.normalizedPath)
asyncSpawn self.client.notifyTextDocumentClosedChannel.send(document.normalizedPath)
# asyncSpawn self.client.notifyClosedTextDocument(document.localizedPath)
asyncSpawn self.client.notifyTextDocumentClosedChannel.send(document.localizedPath)

if self.documentHandles.len == 0:
self.stop()
Expand Down
8 changes: 4 additions & 4 deletions src/text/text_document.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1100,7 +1100,6 @@ proc newTextDocument*(
allTextDocuments.add result

var self = result
self.filename = filename
self.currentTree = TSTree()
self.appFile = app
self.workspace = services.getService(Workspace).get
Expand All @@ -1109,6 +1108,7 @@ proc newTextDocument*(
self.vfs = services.getService(VFSService).get.vfs
self.createLanguageServer = createLanguageServer
self.buffer = initBuffer(content = "", remoteId = getNextBufferId())
self.filename = self.vfs.normalize(filename)

self.indentStyle = IndentStyle(kind: Spaces, spaces: 2)

Expand Down Expand Up @@ -1183,7 +1183,7 @@ proc saveAsync(self: TextDocument) {.async.} =
self.onSaved.invoke()

method save*(self: TextDocument, filename: string = "", app: bool = false) =
self.filename = if filename.len > 0: filename else: self.filename
self.filename = if filename.len > 0: self.vfs.normalize(filename) else: self.filename
logScope lvlInfo, &"[save] '{self.filename}'"

if self.filename.len == 0:
Expand Down Expand Up @@ -1316,7 +1316,7 @@ proc setFileReadOnlyAsync*(self: TextDocument, readOnly: bool): Future[bool] {.a
return false

proc setFileAndContent*[S: string | Rope](self: TextDocument, filename: string, content: sink S) =
let filename = if filename.len > 0: filename else: self.filename
let filename = if filename.len > 0: self.vfs.normalize(filename) else: self.filename
if filename.len == 0:
log lvlError, &"save: Missing filename"
return
Expand All @@ -1341,7 +1341,7 @@ proc setFileAndContent*[S: string | Rope](self: TextDocument, filename: string,
self.onLoaded.invoke self

method load*(self: TextDocument, filename: string = "") =
let filename = if filename.len > 0: filename else: self.filename
let filename = if filename.len > 0: self.vfs.normalize(filename) else: self.filename
if filename.len == 0:
log lvlError, &"save: Missing filename"
return
Expand Down
Loading

0 comments on commit ad83d2f

Please sign in to comment.