Skip to content

Commit

Permalink
Add jump back from goto definition (#2201)
Browse files Browse the repository at this point in the history
  • Loading branch information
fox0430 authored Nov 19, 2024
1 parent 5f7f5f7 commit 8e0a179
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.. _#2201: https://github.com/fox0430/moe/pull/2201

Added
.....

- `#2201`_ Add jump back from goto definition

1 change: 1 addition & 0 deletions documents/howtouse.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
| <kbd>**z**</kbd> <kbd>**R**</kbd></br> | Delete fold lines |
| <kbd>**Ctrl**</kbd> <kbd>**s**</kbd></br> | Selection Range (LSP) |
| <kbd>**Space**</kbd> <kbd>**o**</kbd></br> | Document Symbol (LSP) |
| <kbd>**Ctrl**</kbd> <kbd>**o**</kbd></br> | Jump Back from LSP Goto Definition |

</details>

Expand Down
28 changes: 23 additions & 5 deletions src/moepkg/bufferstatus.nim
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ type
codeLenses*: seq[CodeLens] # Lsp CodeLens
selectionRanges*: seq[SelectionRange] # Lsp SelectionRange
documentSymbols*: seq[DocumentSymbol] # Lsp DocumentSybol
gotoDefinitionSource: Option[BufferLocation] # The position before LSP Goto definition

var
countAddedBuffer = 0
Expand Down Expand Up @@ -316,10 +317,14 @@ proc isUpdate*(bufStatuses: seq[BufferStatus]): bool =
for b in bufStatuses:
if b.isUpdate: return true

proc checkBufferExist*(bufStatus: seq[BufferStatus], path: Runes): Option[int] =
for index, buf in bufStatus:
if buf.path == path:
return some(index)
proc checkBufferExist*(
bufStatus: seq[BufferStatus],
path: Runes | string): Option[int] =

let runes = path.toRunes
for index, buf in bufStatus:
if buf.path == runes:
return some(index)

proc absolutePath*(bufStatus: BufferStatus): Runes =
if isAbsolute($bufStatus.path):
Expand Down Expand Up @@ -384,7 +389,7 @@ proc initBufferStatus*(
return Result[BufferStatus, string].ok b

proc initBufferStatus*(
mode: Mode): Result[BufferStatus, string] =
mode: Mode = Mode.normal): Result[BufferStatus, string] =
## Return a BufferStatus for a new empty buffer.

var b = BufferStatus(
Expand Down Expand Up @@ -451,3 +456,16 @@ proc updateSyntaxCheckerResults*(
bufStatus.syntaxCheckResults = r.get

return Result[(), string].ok ()

proc setGotoDefinitionSource*(b: BufferStatus, l: BufferLocation) {.inline.} =
b.gotoDefinitionSource = some(l)

proc getGotoDefinitionSource*(
b: BufferStatus,
clear: bool = true): Option[BufferLocation] =

if b.gotoDefinitionSource.isSome:
let l = b.gotoDefinitionSource
if clear:
b.gotoDefinitionSource = none(BufferLocation)
return l
1 change: 1 addition & 0 deletions src/moepkg/helputils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ zd - Delete folding lines
zD - Delete all folding lines
Ctrl-s - Selection Range (LSP)
Space o - Document Symbol (LSP)
Ctrl-o - Jump Back from LSP Goto Definition
# Register
Expand Down
2 changes: 1 addition & 1 deletion src/moepkg/independentutils.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#[###################### GNU General Public License 3.0 ######################]#
# #
# Copyright (C) 2017─2023 Shuhei Nogawa #
# Copyright (C) 2017─2024 Shuhei Nogawa #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
Expand Down
14 changes: 14 additions & 0 deletions src/moepkg/lsp/handler.nim
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,10 @@ proc openWindowAndGotoDefinition(
l: BufferLocation): Result[(), string] =
## Goto definition and Goto TypeDefinition.

let
beforePath = $currentBufStatus.path
beforePosition = currentMainWindowNode.bufferPosition

if l.path == $currentBufStatus.absolutePath:
currentMainWindowNode.currentLine = l.range.first.line
currentMainWindowNode.currentColumn = l.range.first.column
Expand Down Expand Up @@ -634,6 +638,16 @@ proc openWindowAndGotoDefinition(
jumpLine(currentBufStatus, currentMainWindowNode, l.range.first.line)
currentMainWindowNode.currentColumn = l.range.first.column

block:
let p = BufferPosition(
line: beforePosition.line,
column: beforePosition.column)
currentBufStatus.setGotoDefinitionSource(BufferLocation(
path: beforePath,
range: BufferRange(
first: p,
last: p)))

return Result[(), string].ok ()

proc lspDeclaration(
Expand Down
31 changes: 30 additions & 1 deletion src/moepkg/normalmode.nim
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,32 @@ proc requestGotoTypeDefinition(status: var EditorStatus) =
if r.isErr:
status.commandLine.writeLspTypeDefinitionError(r.error)

proc jumpBackFromGotoDefinitionSource(status: var EditorStatus) =
let location = currentBufStatus.getGotoDefinitionSource
if location.isNone:
# Not found
return

let
path = location.get.path
bufferIndex = status.bufStatus.checkBufferExist(path)
if bufferIndex.isSome:
status.changeCurrentBuffer(bufferIndex.get)
else:
let err = status.addNewBufferInCurrentWin($path)
if err.isErr:
status.commandLine.writeFileOpenError(location.get.path)
return

status.resize

currentMainWindowNode.currentLine = min(
currentBufStatus.buffer.high,
location.get.range.first.line)
currentMainWindowNode.currentColumn = min(
currentBufStatus.buffer[currentMainWindowNode.currentLine].high,
location.get.range.first.column)

proc requestGotoImplementation(status: var EditorStatus) =
if not status.lspClients.contains(currentBufStatus.langId):
debug "lsp client is not ready"
Expand Down Expand Up @@ -1656,6 +1682,8 @@ proc normalCommand(status: var EditorStatus, commands: Runes): Option[Rune] =
status.requestDocumentLink
elif key == ord('G'):
currentBufStatus.moveToLastLine(currentMainWindowNode)
elif isCtrlO(key):
status.jumpBackFromGotoDefinitionSource
elif isCtrlU(key):
return status.halfPageUpCommand
elif isCtrlD(key):
Expand Down Expand Up @@ -1955,7 +1983,8 @@ proc isNormalModeCommand*(
$command == "L" or
$command == "%" or
$command == "K" or
isCtrlS(command):
isCtrlS(command) or
isCtrlO(command):
result = InputState.Valid

elif isDigit(command[0]):
Expand Down
96 changes: 96 additions & 0 deletions tests/tbufferstatus.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#[###################### GNU General Public License 3.0 ######################]#
# #
# Copyright (C) 2017─2024 Shuhei Nogawa #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
#[############################################################################]#

import std/[unittest, importutils, options]

import pkg/results

import moepkg/independentutils

import moepkg/bufferstatus {.all.}

suite "setGotoDefinitionSource":
privateAccess(BufferStatus)

test "Basic":
var b = initBufferStatus().get
let l = BufferLocation(
path: "/path",
range: BufferRange(
first: BufferPosition(line: 0, column: 1),
last: BufferPosition(line: 0, column: 1)))

b.setGotoDefinitionSource(l)

check b.gotoDefinitionSource.get == l

test "Overwrite":
var b = initBufferStatus().get

b.setGotoDefinitionSource(BufferLocation(
path: "/path",
range: BufferRange(
first: BufferPosition(line: 0, column: 1),
last: BufferPosition(line: 0, column: 1))))

let l = BufferLocation(
path: "/dir/path/",
range: BufferRange(
first: BufferPosition(line: 1, column: 2),
last: BufferPosition(line: 1, column: 2)))

b.setGotoDefinitionSource(l)

check b.gotoDefinitionSource.get == l

suite "getGotoDefinitionSource":
privateAccess(BufferStatus)

test "Empty":
var b = initBufferStatus().get

check b.getGotoDefinitionSource.isNone

test "Basic":
var b = initBufferStatus().get

let l = BufferLocation(
path: "/path",
range: BufferRange(
first: BufferPosition(line: 0, column: 1),
last: BufferPosition(line: 0, column: 1)))

b.gotoDefinitionSource = some(l)

check b.getGotoDefinitionSource.get == l
check b.getGotoDefinitionSource.isNone

test "Peek":
var b = initBufferStatus().get

let l = BufferLocation(
path: "/path",
range: BufferRange(
first: BufferPosition(line: 0, column: 1),
last: BufferPosition(line: 0, column: 1)))

b.gotoDefinitionSource = some(l)

check b.getGotoDefinitionSource(clear = false).get == l
check b.getGotoDefinitionSource.isSome
2 changes: 1 addition & 1 deletion tests/tlsphandler.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1883,7 +1883,7 @@ suite "lsp: handleLspResponse":
assert status.lspInitialize(workspaceRoot, LangId).isOk

var isTimeout = true
for _ in 0 .. 120:
for _ in 0 .. 180:
const Timeout = 1000
let readable = lspClient.readable(Timeout).get
if not readable:
Expand Down
97 changes: 96 additions & 1 deletion tests/tnormalmode.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import pkg/results
import moepkg/syntax/highlite
import moepkg/[registers, settings, editorstatus, gapbuffer, unicodeext,
bufferstatus, ui, windownode, quickrunutils, viewhighlight,
folding, editorview]
folding, editorview, independentutils]

import utils

Expand Down Expand Up @@ -4428,3 +4428,98 @@ suite "Normal mode: requestGotoDefinition":
status.requestGotoDefinition

status.update

suite "Normal mode: jumpBackFromGotoDefinitionSource":
const TestFileBuffer = "123\n123\n"

var status: EditorStatus

let
currentDir = getCurrentDir()
testDir = currentDir / "jumpBackTest"
testFilePath1 = testDir / "file1"
testFilePath2 = testDir / "file2"

setup:
createDir(testDir)


writeFile(testFilePath1, TestFileBuffer)
writeFile(testFilePath2, "a\n")

status = initEditorStatus()
status.settings.lsp.enable = false

teardown:
removeDir(testDir)

test "Empty":
assert status.addNewBufferInCurrentWin(testFilePath1).isOk
assert status.addNewBufferInCurrentWin(testFilePath2).isOk

status.resize(100, 100)
status.update

status.jumpBackFromGotoDefinitionSource

status.update

check currentBufStatus.path == testFilePath2.toRunes
check currentBufStatus.getGotoDefinitionSource.isNone

check currentMainWindowNode.bufferPosition == BufferPosition(
line: 0,
column: 0)

test "Basic":
assert status.addNewBufferInCurrentWin(testFilePath1).isOk
assert status.addNewBufferInCurrentWin(testFilePath2).isOk

status.resize(100, 100)
status.update

let l = BufferLocation(
path: testFilePath1,
range: BufferRange(
first: BufferPosition(line: 0, column: 1),
last: BufferPosition(line: 0, column: 1)))

currentBufStatus.setGotoDefinitionSource(l)

status.jumpBackFromGotoDefinitionSource

status.update

check currentBufStatus.path == testFilePath1.toRunes
check currentBufStatus.buffer.toRunes == TestFileBuffer.toRunes
check currentBufStatus.getGotoDefinitionSource.isNone

check currentMainWindowNode.bufferPosition == BufferPosition(
line: 0,
column: 1)

test "Basic 2":
assert status.addNewBufferInCurrentWin(testFilePath2).isOk

status.resize(100, 100)
status.update

let l = BufferLocation(
path: testFilePath1,
range: BufferRange(
first: BufferPosition(line: 0, column: 1),
last: BufferPosition(line: 0, column: 1)))

currentBufStatus.setGotoDefinitionSource(l)

status.jumpBackFromGotoDefinitionSource

status.update

check currentBufStatus.path == testFilePath1.toRunes
check currentBufStatus.buffer.toRunes == TestFileBuffer.toRunes
check currentBufStatus.getGotoDefinitionSource.isNone

check currentMainWindowNode.bufferPosition == BufferPosition(
line: 0,
column: 1)

0 comments on commit 8e0a179

Please sign in to comment.