diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
new file mode 100644
index 000000000..3ae48eb9a
--- /dev/null
+++ b/.github/workflows/build.yaml
@@ -0,0 +1,33 @@
+name: Build
+
+on:
+ push:
+ paths-ignore:
+ - 'LICENSE'
+ - '*.md'
+ - 'documents/'
+ - 'docs/'
+ branches:
+ - develop
+ - master
+ pull_request:
+ paths-ignore:
+ - 'LICENSE'
+ - '*.md'
+ - 'documents/'
+ - 'docs/'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ nim: [ '1.4.2', 'stable', 'devel' ]
+ name: Build on ${{ matrix.nim }}
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup nim
+ uses: jiro4989/setup-nim-action@v1
+ with:
+ nim-version: ${{ matrix.nim }}
+ - run: nimble build -y
diff --git a/.github/workflows/actions.yaml b/.github/workflows/test.yaml
similarity index 94%
rename from .github/workflows/actions.yaml
rename to .github/workflows/test.yaml
index 840895c05..3d5e54b18 100644
--- a/.github/workflows/actions.yaml
+++ b/.github/workflows/test.yaml
@@ -40,7 +40,7 @@ jobs:
# - macOS-latest
# - windows-latest
env:
- NIM_VERSION: 1.4.8
+ NIM_VERSION: stable
steps:
- uses: actions/checkout@v1
- run: |
@@ -88,8 +88,3 @@ jobs:
- name: Run integtation test
run: shpec ./shpec.sh
-
- - name: Build on Nim devel
- run: |
- choosenim -y devel
- nimble build
diff --git a/README.md b/README.md
index 629d4c110..6a1fd5797 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ A command line based editor inspired by vi/vim written in Nim.
This project's goal is a very customizable, high productivity, user friendly, high performance and funny animation editor.
-![moe](https://user-images.githubusercontent.com/15966436/93508284-5fa0ca00-f959-11ea-8282-d64f540e0c54.png)
+![moe](https://user-images.githubusercontent.com/15966436/146791140-e020a07f-7ca1-4bfd-a6a4-f20f4c7885db.png)
## Features
diff --git a/documents/howtouse.md b/documents/howtouse.md
index ec0ca6837..e0212bbc4 100644
--- a/documents/howtouse.md
+++ b/documents/howtouse.md
@@ -60,6 +60,7 @@
| **Z** **Z**
Write current file and exit | **Z** **Q**
Same as `:q!` | **Ctrl** **w** **c**
Close current window | **?**
`keyword` Search backwards |
| **/**
`keyword` Search forwards | **\\** **r**
Quick Run | **s** OR **c****u**
Delete current charater and enter insert mode | **y****{**
Yank to the previous blank line |
| **y****}**
Yank to the next blank line | **y****l**
Yank a character| **X** OR **d****h**
Cut a character before cursor | **g****a**
Show current character info |
+| **t****x**
Move to the left of the next ```x``` (any character) on the current line | **T****x**
Move to the right of the back ```x ``` (any character) on the current line | **y****t**
**Any key**
Yank characters to an any character | **c****f**
**Any key**
Delete characters to an any character and enter insert mode |
diff --git a/example/moerc.toml b/example/moerc.toml
index 5d93cf3e7..65f9b387a 100644
--- a/example/moerc.toml
+++ b/example/moerc.toml
@@ -67,9 +67,9 @@ enable = false
allBuffer = false
-[StatusBar]
+[StatusLine]
-multipleStatusBar = true
+multipleStatusLine = true
merge = false
diff --git a/moe.nimble b/moe.nimble
index a30a33936..383d15dd8 100644
--- a/moe.nimble
+++ b/moe.nimble
@@ -1,6 +1,6 @@
# Package
-version = "0.2.8.0"
+version = "0.3.0"
author = "fox0430"
description = "A command lined based text editor"
license = "GPLv3"
@@ -10,10 +10,12 @@ bin = @["moe"]
# Dependencies
requires "nim >= 1.4.2"
-requires "https://github.com/walkre-niboshi/nim-ncurses >= 1.0.2"
-requires "unicodedb >= 0.9.0"
-requires "parsetoml >= 0.4.0"
+requires "ncurses >= 1.0.2"
+requires "unicodedb >= 0.10.0"
+requires "parsetoml >= 0.6.0"
task release, "Build for release":
- exec "nim c -o:moe -d:release src/moe"
+ exec "nimble build -d:release"
+task debug, "Build for debug":
+ exec "nimble build -d:debug --debugger:native --verbose -y"
diff --git a/shpec.sh b/shpec.sh
index c6b80e9d7..d3394e390 100644
--- a/shpec.sh
+++ b/shpec.sh
@@ -43,7 +43,7 @@ describe "moe is an editor"
describe "invocation options"
it "can display it's version"
- assert equal `moe -v | grep -oPq "^moe v\d+\.\d+\.\d+\.\d+$";echo $?` 0
+ assert equal `moe -v | grep -oPq "^moe v\d+\.\d+\.\d+$";echo $?` 0
end
it "can display command line options"
diff --git a/src/moe.nim b/src/moe.nim
index 7ff1724a7..2c6a53ddb 100644
--- a/src/moe.nim
+++ b/src/moe.nim
@@ -1,4 +1,4 @@
-import os, times
+import std/[os, times]
import moepkg/[ui, editorstatus, normalmode, insertmode, visualmode,
replacemode, filermode, exmode, buffermanager, logviewer,
cmdlineoption, bufferstatus, help, recentfilemode, quickrun,
@@ -17,6 +17,18 @@ proc loadPersistData(status: var EditorStatus) =
currentMainWindowNode.restoreCursorPostion(currentBufStatus,
status.lastPosition)
+proc addBufferStatus(status: var EditorStatus,
+ parsedList: CmdParsedList) =
+
+ if parsedList.path.len > 0:
+ for path in parsedList.path:
+ if dirExists(path):
+ status.addNewBuffer(path, Mode.filer)
+ else:
+ status.addNewBuffer(path)
+ else:
+ status.addNewBuffer
+
proc initEditor(): EditorStatus =
let parsedList = parseCommandLineOption(commandLineParams())
@@ -33,14 +45,10 @@ proc initEditor(): EditorStatus =
exitUi()
quit())
- if parsedList.len > 0:
- for p in parsedList:
- if dirExists(p.filename):
- result.addNewBuffer(p.filename, Mode.filer)
- else:
- result.addNewBuffer(p.filename)
- else:
- result.addNewBuffer
+ if parsedList.isReadonly:
+ result.isReadonly = true
+
+ result.addBufferStatus(parsedList)
result.loadPersistData
diff --git a/src/moepkg/backup.nim b/src/moepkg/backup.nim
index 5a6986c31..3e187c776 100644
--- a/src/moepkg/backup.nim
+++ b/src/moepkg/backup.nim
@@ -1,4 +1,4 @@
-import os, times, re
+import std/[os, times, re]
import settings, unicodeext, fileutils, bufferstatus, gapbuffer, messages,
commandline
diff --git a/src/moepkg/bookmark.nim b/src/moepkg/bookmark.nim
index 32bcac530..348d0dc74 100644
--- a/src/moepkg/bookmark.nim
+++ b/src/moepkg/bookmark.nim
@@ -1,4 +1,4 @@
-import os
+import std/os
type Bookmark* = object
path*: string
diff --git a/src/moepkg/buffermanager.nim b/src/moepkg/buffermanager.nim
index dae5ef2a0..385910b09 100644
--- a/src/moepkg/buffermanager.nim
+++ b/src/moepkg/buffermanager.nim
@@ -1,4 +1,4 @@
-import terminal, os, heapqueue, times
+import std/[terminal, os, heapqueue, times]
import gapbuffer, ui, editorstatus, unicodeext, highlight, window, movement,
color, bufferstatus
diff --git a/src/moepkg/bufferstatus.nim b/src/moepkg/bufferstatus.nim
index 0166fc04c..c2387d29d 100644
--- a/src/moepkg/bufferstatus.nim
+++ b/src/moepkg/bufferstatus.nim
@@ -1,4 +1,4 @@
-import tables, times, options
+import std/[tables, times, options]
import syntax/highlite
import gapbuffer, unicodeext
@@ -40,6 +40,7 @@ type BufferStatus* = object
mode* : Mode
prevMode* : Mode
lastSaveTime*: DateTime
+ isReadonly*: bool
proc initBufferStatus*(path: seq[Rune], mode: Mode): BufferStatus {.inline.} =
BufferStatus(isUpdate: true, path: path, mode: mode, lastSaveTime: now())
diff --git a/src/moepkg/build.nim b/src/moepkg/build.nim
index c16096d93..c997ad6b6 100644
--- a/src/moepkg/build.nim
+++ b/src/moepkg/build.nim
@@ -1,4 +1,4 @@
-import os, osproc, strformat, unicode
+import std/[os, osproc, strformat, unicode]
import syntax/highlite
proc build*(filename, workspaceRoot,
diff --git a/src/moepkg/clipboard.nim b/src/moepkg/clipboard.nim
index 046dc8115..a8beb72cd 100644
--- a/src/moepkg/clipboard.nim
+++ b/src/moepkg/clipboard.nim
@@ -1,4 +1,4 @@
-import unicode, os
+import std/[unicode, os]
import independentutils, platform, settings
proc runesToStrings(runes: seq[seq[Rune]]): string =
diff --git a/src/moepkg/cmdlineoption.nim b/src/moepkg/cmdlineoption.nim
index a48e97458..fa7acd78f 100644
--- a/src/moepkg/cmdlineoption.nim
+++ b/src/moepkg/cmdlineoption.nim
@@ -1,6 +1,8 @@
-import parseopt, pegs, os, strformat
+import std/[parseopt, pegs, os, strformat]
-type CmdParsedList* = seq[tuple[filename: string]]
+type CmdParsedList* = object
+ path*: seq[string]
+ isReadonly*: bool
proc staticReadVersionFromNimble: string {.compileTime.} =
let peg = """@ "version" \s* "=" \s* \" {[0-9.]+} \" @ $""".peg
@@ -34,6 +36,7 @@ Usage:
moe [file] Edit file
Arguments:
+ -R Readonly mode
-h, --help Print this help
-v, --version Print version
"""
@@ -59,11 +62,12 @@ proc parseCommandLineOption*(line: seq[string]): CmdParsedList =
for kind, key, val in parsedLine.getopt():
case kind:
of cmdArgument:
- result.add((filename: key))
+ result.path.add(key)
of cmdShortOption:
case key:
of "v": writeVersion()
of "h": writeHelp()
+ of "R": result.isReadonly = true
else: writeCmdLineError(kind, key)
of cmdLongOption:
case key:
diff --git a/src/moepkg/color.nim b/src/moepkg/color.nim
index 4e4fc4e5f..6509ccf58 100644
--- a/src/moepkg/color.nim
+++ b/src/moepkg/color.nim
@@ -1,5 +1,5 @@
+import std/[strutils, tables, macros, strformat]
import ncurses
-import strutils, tables, macros, strformat
# maps annotations of the enum to a hexToColor table
macro mapAnnotationToTable(args: varargs[untyped]): untyped =
diff --git a/src/moepkg/commandline.nim b/src/moepkg/commandline.nim
index 927ebace2..d863b4684 100644
--- a/src/moepkg/commandline.nim
+++ b/src/moepkg/commandline.nim
@@ -1,4 +1,4 @@
-import terminal
+import std/terminal
import ui, unicodeext, color
type CommandLine* = object
diff --git a/src/moepkg/commandview.nim b/src/moepkg/commandview.nim
index dd0b6e8c8..02f636321 100644
--- a/src/moepkg/commandview.nim
+++ b/src/moepkg/commandview.nim
@@ -1,4 +1,4 @@
-import terminal, strutils, sequtils, strformat, os, algorithm
+import std/[terminal, strutils, sequtils, strformat, os, algorithm]
import ui, unicodeext, fileutils, color, commandline
type ExModeViewStatus = object
@@ -239,13 +239,12 @@ proc clearCommandBuffer(exStatus: var ExModeViewStatus) =
proc deleteCommandBuffer(exStatus: var ExModeViewStatus) =
if exStatus.buffer.len > 0:
if exStatus.buffer.len < terminalWidth(): dec(exStatus.cursorX)
- exStatus.buffer.delete(exStatus.currentPosition - 1,
- exStatus.currentPosition - 1)
+ exStatus.buffer.delete(exStatus.currentPosition - 1)
dec(exStatus.currentPosition)
proc deleteCommandBufferCurrentPosition(exStatus: var ExModeViewStatus) =
if exStatus.buffer.len > 0 and exStatus.currentPosition < exStatus.buffer.len:
- exStatus.buffer.delete(exStatus.cursorX - 1, exStatus.cursorX - 1)
+ exStatus.buffer.delete(exStatus.cursorX - 1)
if exStatus.currentPosition > exStatus.buffer.len:
dec(exStatus.currentPosition)
@@ -657,6 +656,9 @@ proc getKeyOnceAndWriteCommandView*(
status.commandLine.window.moveLeft(exStatus)
elif isRightkey(key):
exStatus.moveRight
+ if status.settings.popUpWindowInExmode:
+ status.deletePopUpWindow
+ status.update
elif isUpKey(key):
if isSearch: setPrevSearchHistory()
else: setPrevCommandHistory()
diff --git a/src/moepkg/configmode.nim b/src/moepkg/configmode.nim
index 2671fbdee..de2f99cb6 100644
--- a/src/moepkg/configmode.nim
+++ b/src/moepkg/configmode.nim
@@ -1,4 +1,4 @@
-import terminal, times, strutils
+import std/[terminal, times, strutils]
import gapbuffer, ui, editorstatus, unicodeext, window, movement, settings,
bufferstatus, color, highlight, search, editor
diff --git a/src/moepkg/cursor.nim b/src/moepkg/cursor.nim
index 7e3485434..16779c0d4 100644
--- a/src/moepkg/cursor.nim
+++ b/src/moepkg/cursor.nim
@@ -1,4 +1,4 @@
-import deques, strformat
+import std/[deques, strformat]
import editorview, unicodeext
type CursorPosition* = object
diff --git a/src/moepkg/debugmode.nim b/src/moepkg/debugmode.nim
index 38b7071a3..4e5b35fcc 100644
--- a/src/moepkg/debugmode.nim
+++ b/src/moepkg/debugmode.nim
@@ -1,4 +1,4 @@
-import terminal, times, strformat, options
+import std/[terminal, times, strformat, options]
import gapbuffer, ui, unicodeext, highlight, color, window, bufferstatus,
movement, settings
diff --git a/src/moepkg/diffviewer.nim b/src/moepkg/diffviewer.nim
index 88a335147..e2fc004d0 100644
--- a/src/moepkg/diffviewer.nim
+++ b/src/moepkg/diffviewer.nim
@@ -1,4 +1,4 @@
-import times, terminal
+import std/[times, terminal]
import editorstatus, unicodeext, bufferstatus, highlight, color, gapbuffer, ui,
movement, window
diff --git a/src/moepkg/editor.nim b/src/moepkg/editor.nim
index 4ee95dd77..f9ac68373 100644
--- a/src/moepkg/editor.nim
+++ b/src/moepkg/editor.nim
@@ -1,4 +1,4 @@
-import strutils, sequtils, strformat, options
+import std/[strutils, sequtils, strformat, options]
import syntax/highlite
import editorstatus, ui, gapbuffer, unicodeext, undoredostack, window,
bufferstatus, movement, messages, settings, register, commandline
@@ -227,7 +227,8 @@ proc basicNewLine(bufStatus: var BufferStatus,
if first <= last:
let oldLine = bufStatus.buffer[windowNode.currentLine]
var newLine = bufStatus.buffer[windowNode.currentLine]
- newLine.delete(first, last)
+ for _ in first .. last:
+ newLine.delete(first)
if oldLine != newLine:
bufStatus.buffer[windowNode.currentLine] = newLine
@@ -266,7 +267,7 @@ proc basicInsrtIndent(bufStatus: var BufferStatus,
if oldLine != newLine:
bufStatus.buffer[currentLine + 1] = newLine
-proc insertIndetWhenPairOfParen(bufStatus: var BufferStatus,
+proc insertIndentWhenPairOfParen(bufStatus: var BufferStatus,
windowNode: WindowNode,
autoIndent: bool,
tabStop: int) =
@@ -318,12 +319,17 @@ proc insertIndentInNimForKeyEnter(bufStatus: var BufferStatus,
if line.len > 0:
# Auto indent if the current line are "var", "let", "const".
# And, if finish the current line with ':', "object"
- if (currentColumn == line.len) and
- (line.splitWhitespace == @[ru "var"] or
- line.splitWhitespace == @[ru "let"] or
- line.splitWhitespace == @[ru "const"] or
- (line.len > 6 and line[line.len - 6 .. ^1] == ru "object") or
- line[^1] == ru ':'):
+ if currentColumn == line.len and (
+ (line.len > 2 and
+ line.splitWhitespace == @[ru "var"] or
+ line.splitWhitespace == @[ru "let"]) or
+ (line.len > 4 and
+ line.splitWhitespace == @[ru "const"]) or
+ (line.len > 4 and
+ line.splitWhitespace[^1] == (ru "object")) or
+ line[^1] == (ru ':') or
+ line[^1] == (ru '=')
+ ):
let
count = countRepeat(line, Whitespace, 0) + tabStop
oldLine = bufStatus.buffer[windowNode.currentLine + 1]
@@ -350,7 +356,7 @@ proc insertIndentInNimForKeyEnter(bufStatus: var BufferStatus,
# if previous col is the unclosed paren.
elif currentColumn > 0 and isOpenParen(line[currentColumn - 1]):
- bufStatus.insertIndetWhenPairOfParen(windowNode, autoIndent, tabStop)
+ bufStatus.insertIndentWhenPairOfParen(windowNode, autoIndent, tabStop)
else:
bufStatus.basicInsrtIndent(windowNode)
bufStatus.basicNewLine(windowNode, autoIndent, tabStop)
@@ -406,7 +412,7 @@ proc insertIndentInClangForKeyEnter(bufStatus: var BufferStatus,
if currentColumn > 0 :
# if previous col is the unclosed paren.
if line.len > 0 and isOpenParen(line[currentColumn - 1]):
- bufStatus.insertIndetWhenPairOfParen(windowNode, autoIndent, tabStop)
+ bufStatus.insertIndentWhenPairOfParen(windowNode, autoIndent, tabStop)
else:
bufStatus.basicInsrtIndent(windowNode)
bufStatus.basicNewLine(windowNode, autoIndent, tabStop)
@@ -702,7 +708,7 @@ proc deleteIndent*(bufStatus: var BufferStatus,
if numOfDeleteSpace > 0:
var newLine = bufStatus.buffer[windowNode.currentLine]
- for i in 0 ..< numOfDeleteSpace: newLine.delete(0, 0)
+ for i in 0 ..< numOfDeleteSpace: newLine.delete(0)
if oldLine != newLine:
bufStatus.buffer[windowNode.currentLine] = newLine
@@ -720,7 +726,8 @@ proc deleteCharactersBeforeCursorInCurrentLine*(bufStatus: var BufferStatus,
oldLine = bufStatus.buffer[currentLine]
var newLine = bufStatus.buffer[currentLine]
- newLine.delete(0, currentColumn - 1)
+ for _ in 0 ..< currentColumn:
+ newLine.delete(0)
if newLine != oldLine: bufStatus.buffer[currentLine] = newLine
@@ -862,30 +869,17 @@ proc deleteCharacters*(bufStatus: var BufferStatus,
inc(bufStatus.countChange)
bufStatus.isUpdate = true
-# TODO: Delete deleteCurrentCharacter()
-proc deleteCurrentCharacter*(bufStatus: var BufferStatus,
- windowNode: WindowNode,
- autoDeleteParen: bool) =
-
- let oldLine = bufStatus.buffer[windowNode.currentLine]
-
- deleteCharacter(bufStatus,
- windowNode.currentLine,
- windowNode.currentColumn,
- autoDeleteParen)
-
- if oldLine != bufStatus.buffer[windowNode.currentLine]:
- if bufStatus.buffer[windowNode.currentLine].len < 1:
- windowNode.currentColumn = 0
- windowNode.expandedColumn = 0
- elif bufStatus.buffer[windowNode.currentLine].len > 0 and
- windowNode.currentColumn > bufStatus.buffer[windowNode.currentLine].high and
- bufStatus.mode != Mode.insert:
- windowNode.currentColumn = bufStatus.buffer[windowNode.currentLine].len - 1
- windowNode.expandedColumn = bufStatus.buffer[windowNode.currentLine].len - 1
-
- inc(bufStatus.countChange)
- bufStatus.isUpdate = true
+# Delete a character in the current position
+#proc deleteCurrentCharacter*(bufStatus: var BufferStatus,
+# windowNode: WindowNode,
+# autoDeleteParen: bool) =
+#
+# const loop = 1
+# bufStatus.deleteCharacters(
+# autoDeleteParen,
+# windowNode.currentLine,
+# windowNode.currentColumn,
+# loop)
# Add the new line and insert indent in Nim
proc insertIndentNimForOpenBlankLine(bufStatus: var BufferStatus,
@@ -898,12 +892,13 @@ proc insertIndentNimForOpenBlankLine(bufStatus: var BufferStatus,
if aboveLine.len > 0:
# Auto indent if the current line are "var", "let", "const".
- # And, if finish the current line with ':', "object"
+ # And, if finish the current line with ':', "object, '='"
if (aboveLine.splitWhitespace == @[ru "var"] or
aboveLine.splitWhitespace == @[ru "let"] or
aboveLine.splitWhitespace == @[ru "const"] or
- (aboveLine.len > 6 and aboveLine[aboveLine.len - 6 .. ^1] == ru "object") or
- aboveLine[^1] == ru ':'):
+ aboveLine.splitWhitespace[^1] == (ru "object") or
+ aboveLine[^1] == (ru ':') or
+ aboveLine[^1] == (ru '=')):
let
count = countRepeat(aboveLine, Whitespace, 0) + tabStop
oldLine = bufStatus.buffer[currentLineNum]
@@ -914,8 +909,8 @@ proc insertIndentNimForOpenBlankLine(bufStatus: var BufferStatus,
bufStatus.buffer[currentLineNum] = newLine
# Auto indent if finish the current line with "or", "and"
- elif ((aboveLine.len > 2 and aboveLine[aboveLine.len - 2 .. ^1] == ru "or") or
- (aboveLine.len > 3 and aboveLine[aboveLine.len - 3 .. ^1] == ru "and")):
+ elif ((aboveLine.len > 2 and (aboveLine.splitWhitespace)[^1] == ru "or") or
+ (aboveLine.len > 3 and (aboveLine.splitWhitespace)[^1] == ru "and")):
let
count = countRepeat(aboveLine, Whitespace, 0) + tabStop
oldLine = bufStatus.buffer[currentLineNum]
@@ -944,8 +939,8 @@ proc insertIndentInPythonForOpenBlankLine(bufStatus: var BufferStatus,
if aboveLine.len > 0:
# if finish the current line with ':', "or", "and" in Python
- if (aboveLine.len > 2 and aboveLine[aboveLine.len - 2 .. ^1] == ru "or") or
- (aboveLine.len > 3 and aboveLine[aboveLine.len - 3 .. ^1] == ru "and") or
+ if (aboveLine.len > 2 and (aboveLine.splitWhitespace)[^1] == ru "or") or
+ (aboveLine.len > 3 and (aboveLine.splitWhitespace)[^1] == ru "and") or
(aboveLine[^1] == ru ':'):
let
count = countRepeat(aboveLine, Whitespace, 0) + tabStop
@@ -1164,7 +1159,8 @@ proc deleteTillPreviousBlankLine*(bufStatus: var BufferStatus,
for i in 0 ..< currentColumn: deletedLine.add oldLine[i]
if deletedLine.len > 0: deletedBuffer.add deletedLine
- newLine.delete(0, currentColumn - 1)
+ for _ in 0 ..< currentColumn:
+ newLine.delete(0)
if oldLine != newLine: bufStatus.buffer[currentLine] = newLine
@@ -1206,7 +1202,8 @@ proc deleteTillNextBlankLine*(bufStatus: var BufferStatus,
var deletedLine: seq[Rune]
for i in currentColumn ..< oldLine.len : deletedLine.add oldLine[i]
- newLine.delete(currentColumn, oldLine.high)
+ for _ in currentColumn .. oldLine.high:
+ newLine.delete(currentColumn)
if oldLine != newLine:
bufStatus.buffer[currentLine] = newLine
@@ -1535,9 +1532,12 @@ proc replaceCharacters*(bufStatus: var BufferStatus,
character: Rune) =
if isEnterKey(character):
- let line = bufStatus.buffer[windowNode.currentLine]
+ let
+ line = bufStatus.buffer[windowNode.currentLine]
+ currentLine = windowNode.currentLine
+ currentColumn = windowNode.currentColumn
for _ in windowNode.currentColumn ..< min(line.len, loop):
- bufStatus.deleteCurrentCharacter(windowNode, autoDeleteParen)
+ bufStatus.deleteCharacter(currentLine, currentColumn, autoDeleteParen)
keyEnter(bufStatus, windowNode, autoIndent, tabStop)
else:
let oldLine = bufStatus.buffer[windowNode.currentLine]
@@ -1597,7 +1597,7 @@ proc autoIndentCurrentLine*(bufStatus: var BufferStatus,
# Delete current indent
for i in 0 ..< oldLine.len:
if oldLine[i] == ru' ':
- newLine.delete(0, 0)
+ newLine.delete(0)
else: break
newLine.insert(indent, 0)
@@ -1800,7 +1800,7 @@ proc modifyNumberTextUnderCurosr*(bufStatus: var BufferStatus,
block:
var col = currentColumn
while newLine.len > 0 and isDigit(newLine[col]):
- newLine.delete(col, col)
+ newLine.delete(col)
if col > newLine.high: col = newLine.high
# Insert the new number string to newLine
diff --git a/src/moepkg/editorstatus.nim b/src/moepkg/editorstatus.nim
index 630f568c2..0a3d3014d 100644
--- a/src/moepkg/editorstatus.nim
+++ b/src/moepkg/editorstatus.nim
@@ -1,9 +1,9 @@
-import strutils, terminal, os, strformat, tables, times, heapqueue, deques,
- times, options
+import std/[strutils, terminal, os, strformat, tables, times, heapqueue, deques,
+ options]
import syntax/highlite
import gapbuffer, editorview, ui, unicodeext, highlight, fileutils,
- undoredostack, window, color, settings, statusline, bufferstatus, cursor,
- tabline, backup, messages, commandline, register, platform
+ window, color, settings, statusline, bufferstatus, cursor, tabline,
+ backup, messages, commandline, register, platform
# Save cursor position when a buffer for a window(file) gets closed.
type LastPosition* = object
@@ -31,6 +31,7 @@ type EditorStatus* = object
autoBackupStatus*: AutoBackupStatus
isSearchHighlight*: bool
lastPosition*: seq[LastPosition]
+ isReadonly*: bool
proc initEditorStatus*(): EditorStatus =
result.currentDir = getCurrentDir().toRunes
@@ -203,7 +204,7 @@ proc saveSearchHistory(history: seq[seq[Rune]]) =
f.writeLine($line)
# Save the cursor position to the file
-proc saveLastPosition(lastPosition: seq[LastPosition]) =
+proc saveLastCursorPosition(lastPosition: seq[LastPosition]) =
let
chaheDir = getHomeDir() / ".cache/moe"
chaheFile = chaheDir / "lastPosition"
@@ -225,7 +226,7 @@ proc exitEditor*(status: EditorStatus) =
saveSearchHistory(status.searchHistory)
if status.settings.persist.cursorPosition:
- saveLastPosition(status.lastPosition)
+ saveLastCursorPosition(status.lastPosition)
exitUi()
@@ -437,10 +438,20 @@ proc initSyntaxHighlight(windowNode: var WindowNode,
proc isLogViewerMode(mode, prevMode: Mode): bool {.inline.} =
(mode == logViewer) or (mode == ex and prevMode == logViewer)
-proc updateLogViewer(status: var Editorstatus, bufferIndex: int) =
- status.bufStatus[bufferIndex].buffer = initGapBuffer(@[ru""])
- for i in 0 ..< status.messageLog.len:
- status.bufStatus[bufferIndex].buffer.insert(status.messageLog[i], i)
+proc updateLogViewer(bufStatus: var BufferStatus,
+ node: var WindowNode,
+ messageLog: seq[seq[Rune]]) =
+
+ bufStatus.buffer = initGapBuffer(@[ru""])
+ for i in 0 ..< messageLog.len:
+ bufStatus.buffer.insert(messageLog[i], i)
+
+ const EMPTY_RESERVEDWORD: seq[ReservedWord] = @[]
+
+ node.highlight = initHighlight(
+ $bufStatus.buffer,
+ EMPTY_RESERVEDWORD,
+ SourceLanguage.langNone)
proc updateDebugModeBuffer(status: var EditorStatus)
@@ -507,14 +518,14 @@ proc update*(status: var EditorStatus) =
not isConfigMode(currentMode, prevMode):
if isLogViewerMode(currentMode, prevMode):
- status.updateLogViewer(node.bufferIndex)
-
- highlight.updateHighlight(
- bufStatus,
- node,
- status.isSearchHighlight,
- status.searchHistory,
- settings)
+ status.bufStatus[node.bufferIndex].updateLogViewer(node, status.messageLog)
+ else:
+ highlight.updateHighlight(
+ bufStatus,
+ node,
+ status.isSearchHighlight,
+ status.searchHistory,
+ settings)
let
startSelectedLine = bufStatus.selectArea.startLine
@@ -636,7 +647,8 @@ proc closeWindow*(status: var EditorStatus,
node: WindowNode,
height, width: int) =
- if currentBufStatus.mode == Mode.normal:
+ if isNormalMode(currentBufStatus.mode, currentBufStatus.prevMode) or
+ isFilerMode(currentBufStatus.mode, currentBufStatus.prevMode):
status.updateLastCursorPostion
if status.mainWindow.numOfMainWindow == 1:
@@ -717,13 +729,17 @@ proc deletePopUpWindow*(status: var Editorstatus) =
proc addNewBuffer*(status: var EditorStatus, filename: string, mode: Mode) =
- let path = if mode == Mode.filer: ru absolutePath(filename) else: ru filename
+ let path = if isFilerMode(mode): ru absolutePath(filename) else: ru filename
status.bufStatus.add(initBufferStatus(path, mode))
let index = status.bufStatus.high
- if mode != Mode.filer:
+ status.bufStatus[index].isReadonly = status.isReadonly
+
+ if mode == Mode.filer:
+ status.bufStatus[index].buffer = initGapBuffer(@[ru ""])
+ else:
if not fileExists(filename):
status.bufStatus[index].buffer = newFile()
else:
@@ -1176,8 +1192,6 @@ proc autoSave(status: var Editorstatus) =
status.messageLog)
status.bufStatus[index].lastSaveTime = now()
-from settings import TomlError, loadSettingFile
-
proc loadConfigurationFile*(status: var EditorStatus) =
status.settings =
try:
diff --git a/src/moepkg/editorview.nim b/src/moepkg/editorview.nim
index 2b09fee6b..4afa8339b 100644
--- a/src/moepkg/editorview.nim
+++ b/src/moepkg/editorview.nim
@@ -1,5 +1,5 @@
-import deques, strutils, math, strformat
-import gapbuffer, ui, unicodeext, highlight, independentutils, color, settings,
+import std/[deques, strutils, math, strformat]
+import gapbuffer, ui, unicodeext, independentutils, color, settings,
bufferstatus, highlight
type EditorView* = object
diff --git a/src/moepkg/exmode.nim b/src/moepkg/exmode.nim
index 4c592f5e6..11a0824eb 100644
--- a/src/moepkg/exmode.nim
+++ b/src/moepkg/exmode.nim
@@ -1,4 +1,4 @@
-import sequtils, strutils, os, terminal, times, options
+import std/[sequtils, strutils, os, terminal, times, options]
import syntax/highlite
import editorstatus, ui, normalmode, gapbuffer, fileutils, editorview,
unicodeext, independentutils, search, highlight, commandview,
@@ -311,8 +311,10 @@ proc startHistoryManager(status: var Editorstatus) =
proc startRecentFileMode(status: var Editorstatus) =
status.changeMode(currentBufStatus.prevMode)
- # :recent is only supported on GNU/Linux
- if CURRENT_PLATFORM != Platforms.linux: return
+ # :recent is only supported on Unix or Unix-like (BSD and Linux)
+ if not (CURRENT_PLATFORM == Platforms.linux or
+ CURRENT_PLATFORM == Platforms.freebsd or
+ CURRENT_PLATFORM == Platforms.openbsd): return
if not fileExists(getHomeDir() / ".local/share/recently-used.xbel"):
status.commandLine.writeOpenRecentlyUsedXbelError(status.messageLog)
@@ -779,8 +781,10 @@ proc editCommand(status: var EditorStatus, path: seq[Rune]) =
status.changeCurrentBuffer(bufferIndex.get)
- currentMainWindowNode.restoreCursorPostion(currentBufStatus,
- status.lastPosition)
+ if not isFilerMode(currentBufStatus.mode):
+ currentMainWindowNode.restoreCursorPostion(
+ currentBufStatus,
+ status.lastPosition)
proc openInHorizontalSplitWindow(status: var Editorstatus, filename: seq[Rune]) =
status.horizontalSplitWindow
@@ -1149,8 +1153,10 @@ proc replaceBuffer(status: var EditorStatus, command: seq[Rune]) =
if searchResult.line > -1:
let oldLine = currentBufStatus.buffer[searchResult.line]
var newLine = currentBufStatus.buffer[searchResult.line]
- newLine.delete(searchResult.column,
- searchResult.column + replaceInfo.searhWord.high)
+
+ for _ in searchResult.column .. searchResult.column + replaceInfo.searhWord.high:
+ newLine.delete(searchResult.column)
+
newLine.insert(replaceInfo.replaceWord, searchResult.column)
if oldLine != newLine:
currentBufStatus.buffer[searchResult.line] = newLine
diff --git a/src/moepkg/filermode.nim b/src/moepkg/filermode.nim
index 321ca4e14..047d5bb18 100644
--- a/src/moepkg/filermode.nim
+++ b/src/moepkg/filermode.nim
@@ -1,7 +1,8 @@
-import os, terminal, strutils, unicodeext, times, algorithm, sequtils, options
+import std/[os, terminal, strutils, times, algorithm, sequtils,
+ options]
import editorstatus, ui, fileutils, editorview, gapbuffer, highlight,
- commandview, highlight, window, color, bufferstatus, settings, messages,
- commandline
+ commandview, window, color, bufferstatus, settings, messages,
+ commandline, unicodeext
type PathInfo = tuple[kind: PathComponent,
path: string,
@@ -77,8 +78,8 @@ proc sortDirList(dirList: seq[PathInfo], sortBy: Sort): seq[PathInfo] =
result.add dirList.sortedByIt(it.lastWriteTime)
when defined(posix):
- from posix import nil
- from posix_utils import nil
+ from std/posix import nil
+ from std/posix_utils import nil
proc isFifo(file: string): bool {.inline.} =
posix.S_ISFIFO(posix_utils.stat(file).st_mode)
@@ -515,6 +516,19 @@ proc filerMode*(status: var EditorStatus) =
let currentBufferIndex = status.bufferIndexInCurrentWindow
+ block:
+ filerStatus = filerStatus.updateDirList(currentBufStatus.path)
+ filerStatus.dirlistUpdate = false
+
+ status.updateFilerView(filerStatus, terminalHeight(), terminalWidth())
+
+ currentMainWindowNode.restoreCursorPostion(
+ currentBufStatus,
+ status.lastPosition)
+
+ status.updateFilerView(filerStatus, terminalHeight(), terminalWidth())
+ filerStatus.viewUpdate = false
+
while isFilerMode(currentBufStatus.mode) and
currentBufferIndex == status.bufferIndexInCurrentWindow:
diff --git a/src/moepkg/fileutils.nim b/src/moepkg/fileutils.nim
index 9f61a99d0..3b9f16243 100644
--- a/src/moepkg/fileutils.nim
+++ b/src/moepkg/fileutils.nim
@@ -1,4 +1,4 @@
-import os, encodings
+import std/[os, encodings]
import gapbuffer, unicodeext
proc normalizePath*(path: seq[Rune]): seq[Rune] =
diff --git a/src/moepkg/gapbuffer.nim b/src/moepkg/gapbuffer.nim
index 16da43c1b..61f0327b8 100644
--- a/src/moepkg/gapbuffer.nim
+++ b/src/moepkg/gapbuffer.nim
@@ -1,4 +1,4 @@
-import macros, strformat
+import std/[macros, strformat]
import undoredostack
export undoredostack
diff --git a/src/moepkg/generalautocomplete.nim b/src/moepkg/generalautocomplete.nim
index 66fcce363..5a1c66a6f 100644
--- a/src/moepkg/generalautocomplete.nim
+++ b/src/moepkg/generalautocomplete.nim
@@ -1,4 +1,4 @@
-import sugar, critbits, options, sequtils
+import std/[sugar, critbits, options]
import unicodedb/properties
import unicodeext, bufferstatus
@@ -55,7 +55,9 @@ proc getTextInBuffers*(
for i, buf in bufStatus:
# 0 is current bufStatus
if i == 0:
- result = buf.buffer.toRunes.dup(
- delete(firstDeletedIndex, lastDeletedIndex))
+ var runeBuf = buf.buffer.toRunes
+ for _ in firstDeletedIndex .. lastDeletedIndex:
+ runeBuf.delete(firstDeletedIndex)
+ result = runeBuf
else:
result.add buf.buffer.toRunes
diff --git a/src/moepkg/help.nim b/src/moepkg/help.nim
index 630abdca5..9830362c1 100644
--- a/src/moepkg/help.nim
+++ b/src/moepkg/help.nim
@@ -1,4 +1,4 @@
-import terminal
+import std/[terminal]
import editorstatus, bufferstatus, ui, movement, unicodeext, gapbuffer, window
const helpsentences = """
@@ -52,6 +52,7 @@ yy or Y - Copy a line
y{ - Yank to the previous blank line
y} - Yank to the next blank line
yl - Yank a character
+yt any - Ynak characters to a any character
p - Paste the clipboard
n - Search forwards
: - Start Ex mode
@@ -71,6 +72,7 @@ ciw - Delete the current word and enter insert mode
ci( or ci) - Delete the inside of round brackets and enter insert mode
ci[ or ci] - Delete the inside of square brackets and enter insert mode
ci{ or ci} - Delete the inside of curly brackets and enter insert mode
+cf any - Delete characters to the any character and enter insert mode
di" - Delete the inside of double quotes
di' - Delete the inside of single quotes
diw - Delete the current word
@@ -79,8 +81,10 @@ di[ or di] - Delete the inside of square brackets
di{ or di} - Delete the inside of curly brackets
* - Search forwards for the word under cursor
# - Search backwards for the word under cursor
-f - Jump to next occurrence
-F - Jump to previous occurence
+f - Move to next any character on the current line
+F - Move to previous any character on the current line
+t - Move to the left of the any character on the current line
+T - Move to the right of the back any character on the current line
Ctrl-k - Move to the next window
Ctrl-j - Move to the previous window
zt - Scroll the screen so the cursor is at the top
diff --git a/src/moepkg/highlight.nim b/src/moepkg/highlight.nim
index 002ff8893..ed379f052 100644
--- a/src/moepkg/highlight.nim
+++ b/src/moepkg/highlight.nim
@@ -1,7 +1,7 @@
-import sequtils, os, strformat, parseutils
+import std/[sequtils, os, strformat, parseutils]
import syntax/highlite
import unicodeext, color
-from strutils import find
+from std/strutils import find
type ColorSegment* = object
firstRow*, firstColumn*, lastRow*, lastColumn*: int
diff --git a/src/moepkg/historymanager.nim b/src/moepkg/historymanager.nim
index f13f833fa..6ebff1c82 100644
--- a/src/moepkg/historymanager.nim
+++ b/src/moepkg/historymanager.nim
@@ -1,6 +1,6 @@
# History manager for automatic backup.
-import re, os, times, terminal, osproc
+import std/[re, os, times, terminal, osproc]
import editorstatus, bufferstatus, unicodeext, ui, movement, gapbuffer,
highlight, color, settings, messages, backup, commandview, fileutils,
editorview, window
diff --git a/src/moepkg/independentutils.nim b/src/moepkg/independentutils.nim
index a4b79a7e2..c21112444 100644
--- a/src/moepkg/independentutils.nim
+++ b/src/moepkg/independentutils.nim
@@ -1,4 +1,4 @@
-import strutils, math, random, osproc
+import std/[strutils, math, random, osproc]
proc numberOfDigits*(x: int): int {.inline.} = x.intToStr.len
diff --git a/src/moepkg/insertmode.nim b/src/moepkg/insertmode.nim
index f4aa8300d..abec6915c 100644
--- a/src/moepkg/insertmode.nim
+++ b/src/moepkg/insertmode.nim
@@ -1,4 +1,4 @@
-import terminal, times, options, unicode
+import std/[terminal, times, options, unicode]
import ui, editorstatus, gapbuffer, window, movement, editor, bufferstatus,
suggestionwindow, settings
@@ -97,8 +97,9 @@ proc insertMode*(status: var EditorStatus) =
elif isEndKey(key):
currentBufStatus.moveToLastOfLine(windowNode)
elif isDcKey(key):
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ windowNode.currentLine,
+ windowNode.currentColumn,
status.settings.autoDeleteParen)
elif isBackspaceKey(key) or isControlH(key):
currentBufStatus.keyBackspace(
diff --git a/src/moepkg/logviewer.nim b/src/moepkg/logviewer.nim
index 83fb0c2bc..666bd7fd9 100644
--- a/src/moepkg/logviewer.nim
+++ b/src/moepkg/logviewer.nim
@@ -1,4 +1,4 @@
-import terminal, times
+import std/[terminal, times]
import ui, editorstatus, unicodeext, movement, bufferstatus, window
proc exitLogViewer*(status: var Editorstatus, height, width: int) {.inline.} =
diff --git a/src/moepkg/messages.nim b/src/moepkg/messages.nim
index ea6af8e1c..53b934b78 100644
--- a/src/moepkg/messages.nim
+++ b/src/moepkg/messages.nim
@@ -1,13 +1,15 @@
-import strformat, os, strutils
+import std/[strformat, os, strutils]
import color, unicodeext, settings, commandline, independentutils
proc writeMessageOnCommandWindow*(commandLine: var CommandLine,
message: string,
color: EditorColorPair) {.inline.} =
+
commandLine.updateCommandBuffer(ru message, color)
proc writeMessageOnCommandWindow*(commandLine: var CommandLine,
message: string) {.inline.} =
+
commandLine.writeMessageOnCommandWindow(message, EditorColorPair.commandBar)
proc writeNoWriteError*(commandLine: var CommandLine, messageLog: var seq[seq[Rune]]) =
@@ -296,3 +298,7 @@ proc writeCurrentCharInfo*(commandLine: var CommandLine, r: Rune) {.inline.} =
eOct = int64(e[0]).toOct(5)
mess = fmt "<{$r}> {e[0]} Hex {normalizeHex($eHex)} Oct {$eOct}"
commandLine.writeMessageOnCommandWindow(mess)
+
+proc writeReadonlyModeWarning*(commandLine: var CommandLine) {.inline.} =
+ const mess = "Warning: Readonly mode"
+ commandLine.writeMessageOnCommandWindow(mess, EditorColorPair.errorMessage)
diff --git a/src/moepkg/movement.nim b/src/moepkg/movement.nim
index 7b2a1a65d..cac721922 100644
--- a/src/moepkg/movement.nim
+++ b/src/moepkg/movement.nim
@@ -1,4 +1,4 @@
-import deques
+import std/deques
import editorstatus, ui, editorview, gapbuffer, unicodeext, window, bufferstatus
template currentLineLen: int = bufStatus.buffer[windowNode.currentLine].len
diff --git a/src/moepkg/normalmode.nim b/src/moepkg/normalmode.nim
index 2d9aef937..4e9d86463 100644
--- a/src/moepkg/normalmode.nim
+++ b/src/moepkg/normalmode.nim
@@ -1,5 +1,4 @@
-from strutils import parseInt
-import terminal, times, strutils
+import std/[terminal, times, strutils]
import editorstatus, ui, gapbuffer, unicodeext, fileutils, undoredostack,
window, movement, editor, search, bufferstatus, quickrun,
messages
@@ -9,9 +8,10 @@ type InputState = enum
Valid
Invalid
-proc searchOneCharactorToEndOfLine(bufStatus: var BufferStatus,
+proc searchOneCharacterToEndOfLine(bufStatus: var BufferStatus,
windowNode: WindowNode,
- rune: Rune) =
+ rune: Rune): int =
+ result = -1
let line = bufStatus.buffer[windowNode.currentLine]
@@ -20,12 +20,13 @@ proc searchOneCharactorToEndOfLine(bufStatus: var BufferStatus,
for col in windowNode.currentColumn + 1 ..< line.len:
if line[col] == rune:
- windowNode.currentColumn = col
+ result = col
break
-proc searchOneCharactorToBeginOfLine(bufStatus: var BufferStatus,
+proc searchOneCharacterToBeginOfLine(bufStatus: var BufferStatus,
windowNode: WindowNode,
- rune: Rune) =
+ rune: Rune): int =
+ result = -1
let line = bufStatus.buffer[windowNode.currentLine]
@@ -33,7 +34,7 @@ proc searchOneCharactorToBeginOfLine(bufStatus: var BufferStatus,
for col in countdown(windowNode.currentColumn - 1, 0):
if line[col] == rune:
- windowNode.currentColumn = col
+ result = col
break
proc searchNextOccurrence(status: var EditorStatus, keyword: seq[Rune]) =
@@ -155,6 +156,10 @@ proc yankWord(status: var EditorStatus, registerName: string) =
status.settings)
proc deleteWord(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
currentBufStatus.deleteWord(
currentMainWindowNode,
@@ -173,6 +178,10 @@ proc deleteWord(status: var EditorStatus, registerName: string) =
# ci command
proc changeInnerCommand(status: var EditorStatus, key: Rune) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
let
currentLine = currentMainWindowNode.currentLine
oldLine = currentBufStatus.buffer[currentLine]
@@ -202,6 +211,10 @@ proc changeInnerCommand(status: var EditorStatus,
key: Rune,
registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
let
currentLine = currentMainWindowNode.currentLine
oldLine = currentBufStatus.buffer[currentLine]
@@ -229,6 +242,10 @@ proc changeInnerCommand(status: var EditorStatus,
# di command
proc deleteInnerCommand(status: var EditorStatus, key: Rune, registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
# Delete inside paren and enter insert mode
if isParen(key):
if registerName.len > 0:
@@ -256,6 +273,10 @@ proc deleteInnerCommand(status: var EditorStatus, key: Rune, registerName: strin
# di command
proc deleteInnerCommand(status: var EditorStatus, key: Rune) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
status.deleteInnerCommand(key, registerName)
@@ -368,6 +389,10 @@ proc yankToNextBlankLine(status: var EditorStatus) =
# dd command
proc deleteLines(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
let
startLine = currentMainWindowNode.currentLine
@@ -382,6 +407,10 @@ proc deleteLines(status: var EditorStatus) =
status.settings)
proc deleteLines(status: var EditorStatus, registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
let
startLine = currentMainWindowNode.currentLine
count = min(
@@ -435,7 +464,60 @@ proc yankCharacters(status: var Editorstatus, registerName: string) =
registerName,
isDelete)
+# yt command
+proc yankCharactersToCharacter(status: var EditorStatus,
+ rune: Rune) =
+
+ let
+ currentColumn = currentMainWindowNode.currentColumn
+ # Get the position of a character
+ position = currentBufStatus.searchOneCharacterToEndOfLine(
+ currentMainWindowNode,
+ rune)
+
+ if position > currentColumn:
+ const
+ isDelete = false
+ registerName = ""
+ currentBufStatus.yankCharacters(
+ status.registers,
+ currentMainWindowNode,
+ status.commandLine,
+ status.messageLog,
+ status.settings,
+ position,
+ registerName,
+ isDelete)
+
+# yt command
+proc yankCharactersToCharacter(status: var EditorStatus,
+ rune: Rune,
+ registerName: string) =
+
+ let
+ currentColumn = currentMainWindowNode.currentColumn
+ # Get the position of a character
+ position = currentBufStatus.searchOneCharacterToEndOfLine(
+ currentMainWindowNode,
+ rune)
+
+ if position > currentColumn:
+ const isDelete = false
+ currentBufStatus.yankCharacters(
+ status.registers,
+ currentMainWindowNode,
+ status.commandLine,
+ status.messageLog,
+ status.settings,
+ position,
+ registerName,
+ isDelete)
+
proc deleteCharacters(status: var EditorStatus, registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
currentBufStatus.deleteCharacters(
status.registers,
registerName,
@@ -445,6 +527,10 @@ proc deleteCharacters(status: var EditorStatus, registerName: string) =
status.settings)
proc deleteCharacters(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
currentBufStatus.deleteCharacters(
status.registers,
@@ -458,6 +544,10 @@ proc deleteCharacters(status: var EditorStatus) =
proc deleteCharactersUntilEndOfLine(status: var EditorStatus,
registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
let lineWidth = currentBufStatus.buffer[currentMainWindowNode.currentLine].len
currentBufStatus.cmdLoop = lineWidth - currentMainWindowNode.currentColumn
@@ -469,6 +559,10 @@ proc deleteCharactersUntilEndOfLine(status: var EditorStatus,
# d$ command
proc deleteCharactersUntilEndOfLine(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
let lineWidth = currentBufStatus.buffer[currentMainWindowNode.currentLine].len
currentBufStatus.cmdLoop = lineWidth - currentMainWindowNode.currentColumn
@@ -483,6 +577,10 @@ proc deleteCharactersUntilEndOfLine(status: var EditorStatus) =
proc deleteCharacterBeginningOfLine(status: var EditorStatus,
registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
currentBufStatus.deleteCharacterBeginningOfLine(
status.registers,
currentMainWindowNode,
@@ -491,6 +589,10 @@ proc deleteCharacterBeginningOfLine(status: var EditorStatus,
# d0 command
proc deleteCharacterBeginningOfLine(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
status.deleteCharacterBeginningOfLine(registerName)
@@ -499,6 +601,10 @@ proc deleteCharacterBeginningOfLine(status: var EditorStatus) =
proc deleteFromCurrentLineToLastLine(status: var EditorStatus,
registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
let
startLine = currentMainWindowNode.currentLine
count = currentBufStatus.buffer.len - currentMainWindowNode.currentLine
@@ -514,6 +620,10 @@ proc deleteFromCurrentLineToLastLine(status: var EditorStatus,
proc deleteLineFromFirstLineToCurrentLine(status: var EditorStatus,
registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const startLine = 0
let count = currentMainWindowNode.currentLine
currentBufStatus.deleteLines(status.registers,
@@ -529,6 +639,10 @@ proc deleteLineFromFirstLineToCurrentLine(status: var EditorStatus,
proc deleteTillPreviousBlankLine(status: var EditorStatus,
registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
currentBufStatus.deleteTillPreviousBlankLine(
status.registers,
currentMainWindowNode,
@@ -536,6 +650,10 @@ proc deleteTillPreviousBlankLine(status: var EditorStatus,
status.settings)
proc deleteTillPreviousBlankLine(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
status.deleteTillPreviousBlankLine(registerName)
@@ -543,6 +661,10 @@ proc deleteTillPreviousBlankLine(status: var EditorStatus) =
proc deleteTillNextBlankLine(status: var EditorStatus,
registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
currentBufStatus.deleteTillNextBlankLine(
status.registers,
currentMainWindowNode,
@@ -551,6 +673,10 @@ proc deleteTillNextBlankLine(status: var EditorStatus,
# X and dh command
proc cutCharacterBeforeCursor(status: var EditorStatus, registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
if currentMainWindowNode.currentColumn > 0:
let
currentColumn = currentMainWindowNode.currentColumn
@@ -564,38 +690,45 @@ proc cutCharacterBeforeCursor(status: var EditorStatus, registerName: string) =
# X and dh command
proc cutCharacterBeforeCursor(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
status.cutCharacterBeforeCursor(registerName)
proc deleteTillNextBlankLine(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
status.deleteTillNextBlankLine(registerName)
proc deleteLineFromFirstLineToCurrentLine(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
status.deleteLineFromFirstLineToCurrentLine(registerName)
proc deleteFromCurrentLineToLastLine(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
status.deleteFromCurrentLineToLastLine(registerName)
-# s and cl commands
-proc deleteCharacterAndEnterInsertMode(status: var EditorStatus) =
- if currentBufStatus.buffer[currentMainWindowNode.currentLine].len > 0:
- let
- lineWidth = currentBufStatus.buffer[currentMainWindowNode.currentLine].len
- cmdLoop = currentBufStatus.cmdLoop
- loop = min(cmdLoop, lineWidth - currentMainWindowNode.currentColumn)
- currentBufStatus.cmdLoop = loop
-
- status.deleteCharacters
-
- status.changeMode(Mode.insert)
-
# s and cl commands
proc deleteCharacterAndEnterInsertMode(status: var EditorStatus,
registerName: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
if currentBufStatus.buffer[currentMainWindowNode.currentLine].len > 0:
let
lineWidth = currentBufStatus.buffer[currentMainWindowNode.currentLine].len
@@ -603,12 +736,21 @@ proc deleteCharacterAndEnterInsertMode(status: var EditorStatus,
loop = min(cmdLoop, lineWidth - currentMainWindowNode.currentColumn)
currentBufStatus.cmdLoop = loop
- status.deleteCharacters
+ status.deleteCharacters(registerName)
status.changeMode(Mode.insert)
+# s and cl commands
+proc deleteCharacterAndEnterInsertMode(status: var EditorStatus) =
+ const registerName = ""
+ status.deleteCharacterAndEnterInsertMode(registerName)
+
# cc/S command
proc deleteCharactersAfterBlankInLine(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
const registerName = ""
currentBufStatus.deleteCharactersAfterBlankInLine(
status.registers,
@@ -616,7 +758,40 @@ proc deleteCharactersAfterBlankInLine(status: var EditorStatus) =
registerName,
status.settings)
+# cf command
+proc deleteCharactersToCharacterAndEnterInsertMode(status: var EditorStatus,
+ rune: Rune,
+ registerName: string) =
+
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
+ let
+ currentColumn = currentMainWindowNode.currentColumn
+ # Get the position of a character
+ position = currentBufStatus.searchOneCharacterToEndOfLine(
+ currentMainWindowNode,
+ rune)
+
+ if position > currentColumn:
+ currentBufStatus.cmdLoop = position - currentColumn + 1
+ status.deleteCharacters
+
+ status.changeMode(Mode.insert)
+
+# cf command
+proc deleteCharactersToCharacterAndEnterInsertMode(status: var EditorStatus,
+ rune: Rune) =
+
+ const registerName = ""
+ status.deleteCharactersToCharacterAndEnterInsertMode(rune, registerName)
+
proc enterInsertModeAfterCursor(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
let lineWidth = currentBufStatus.buffer[currentMainWindowNode.currentLine].len
if lineWidth == 0: discard
elif lineWidth == currentMainWindowNode.currentColumn: discard
@@ -624,11 +799,19 @@ proc enterInsertModeAfterCursor(status: var EditorStatus) =
status.changeMode(Mode.insert)
proc toggleCharacterAndMoveRight(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
currentBufStatus.toggleCharacters(
currentMainWindowNode,
currentBufStatus.cmdLoop)
proc replaceCurrentCharacter(status: var EditorStatus, newCharacter: Rune) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
currentBufStatus.replaceCharacters(
currentMainWindowNode,
status.settings.autoIndent,
@@ -638,12 +821,20 @@ proc replaceCurrentCharacter(status: var EditorStatus, newCharacter: Rune) =
newCharacter)
proc openBlankLineBelowAndEnterInsertMode(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
currentBufStatus.openBlankLineBelow(currentMainWindowNode,
status.settings.autoIndent,
status.settings.tabStop)
status.changeMode(Mode.insert)
proc openBlankLineAboveAndEnterInsertMode(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
currentBufStatus.openBlankLineAbove(currentMainWindowNode,
status.settings.autoIndent,
status.settings.tabStop)
@@ -658,6 +849,23 @@ proc openBlankLineAboveAndEnterInsertMode(status: var EditorStatus) =
status.changeMode(Mode.insert)
+proc moveToFirstNonBlankOfLineAndEnterInsertMode(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
+ currentBufStatus.moveToFirstNonBlankOfLine(currentMainWindowNode)
+ status.changeMode(Mode.insert)
+
+proc moveToEndOfLineAndEnterInsertMode(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
+ let lineLen = currentBufStatus.buffer[currentMainWindowNode.currentLine].len
+ currentMainWindowNode.currentColumn = lineLen
+ status.changeMode(Mode.insert)
+
proc closeCurrentWindow(status: var EditorStatus, height, width: int) =
if status.mainWindow.numOfMainWindow == 1: return
@@ -702,10 +910,20 @@ proc addRegister(status: var EditorStatus, command, registerName: string) =
status.deleteCharacterAndEnterInsertMode(registerName)
elif command.len == 3 and command[0 .. 1] == "ci":
status.changeInnerCommand(command[2].toRune, registerName)
+ elif command.len == 3 and command[0 .. 1] == "yt":
+ status.yankCharactersToCharacter(command[2].toRune, registerName)
+ elif command.len == 3 and command[0 .. 1] == "cf":
+ status.deleteCharactersToCharacterAndEnterInsertMode(
+ command[2].toRune,
+ registerName)
else:
discard
proc pasteFromRegister(status: var EditorStatus, command, name: string) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
if name.len == 0: return
case command:
@@ -753,12 +971,26 @@ proc registerCommand(status: var EditorStatus, command: seq[Rune]) =
cmd == "dgg" or
cmd == "d{" or
cmd == "d}" or
- cmd.len == 3 and cmd[0 .. 1] == "di" or
+ (cmd.len == 3 and cmd[0 .. 1] == "di") or
cmd == "dh" or
cmd == "cl" or cmd == "s" or
- cmd.len == 3 and cmd[0 .. 1] == "ci":
+ (cmd.len == 3 and cmd[0 .. 1] == "ci") or
+ (cmd.len == 3 and cmd[0 .. 1] == "yt") or
+ (cmd.len == 3 and cmd[0 .. 1] == "cf"):
status.addRegister(cmd, $registerName)
+proc pasteAfterCursor(status: var EditorStatus) {.inline.} =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ else:
+ currentBufStatus.pasteAfterCursor(currentMainWindowNode, status.registers)
+
+proc pasteBeforeCursor(status: var EditorStatus) {.inline.} =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ else:
+ currentBufStatus.pasteBeforeCursor(currentMainWindowNode, status.registers)
+
proc isMovementKey(key: Rune): bool =
return isControlK(key) or
isControlJ(key) or
@@ -793,6 +1025,24 @@ proc isChangeModeKey(key: Rune): bool =
key == ord('a') or
key == ord('A')
+proc changeModeToInsertMode(status: var EditorStatus) {.inline.} =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ else:
+ status.changeMode(Mode.insert)
+
+proc changeModeToReplaceMode(status: var EditorStatus) {.inline.} =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ else:
+ status.changeMode(Mode.replace)
+
+proc changeModeToVisualMode(status: var EditorStatus) {.inline.} =
+ status.changeMode(Mode.visual)
+
+proc changeModeToVisualBlockMode(status: var EditorStatus) {.inline.} =
+ status.changeMode(Mode.visualBlock)
+
proc normalCommand(status: var EditorStatus,
commands: seq[Rune],
height, width: int) =
@@ -812,7 +1062,7 @@ proc normalCommand(status: var EditorStatus,
elif isControlJ(key):
status.movePrevWindow
elif isControlV(key):
- status.changeMode(Mode.visualBlock)
+ status.changeModeToVisualBlockMode
elif key == ord('h') or isLeftKey(key) or isBackspaceKey(key):
for i in 0 ..< cmdLoop: currentMainWindowNode.keyLeft
elif key == ord('l') or isRightKey(key):
@@ -883,13 +1133,16 @@ proc normalCommand(status: var EditorStatus,
if secondKey == ord('c'):
status.deleteCharactersAfterBlankInLine
status.enterInsertModeAfterCursor
- if secondKey == ord('l'):
+ elif secondKey == ord('l'):
status.deleteCharacterAndEnterInsertMode
elif secondKey == ord('i'):
let thirdKey = commands[2]
if isParen(thirdKey) or
thirdKey == ord('w'):
status.changeInnerCommand(thirdKey)
+ elif secondKey == ord('f'):
+ let thirdKey = commands[2]
+ status.deleteCharactersToCharacterAndEnterInsertMode(thirdKey)
elif key == ord('d'):
let secondKey = commands[1]
if secondKey == ord('d'):
@@ -934,12 +1187,15 @@ proc normalCommand(status: var EditorStatus,
status.yankToNextBlankLine
elif secondKey == ord('l'):
status.yankCharacters
+ elif secondKey == ord('t'):
+ let thirdKey = commands[2]
+ status.yankCharactersToCharacter(thirdKey)
elif key == ord('Y'):
status.yankLines
elif key == ord('p'):
- currentBufStatus.pasteAfterCursor(currentMainWindowNode, status.registers)
+ status.pasteAfterCursor
elif key == ord('P'):
- currentBufStatus.pasteBeforeCursor(currentMainWindowNode, status.registers)
+ status.pasteBeforeCursor
elif key == ord('>'):
for i in 0 ..< cmdLoop:
currentBufStatus.addIndent(currentMainWindowNode, status.settings.tabStop)
@@ -973,29 +1229,48 @@ proc normalCommand(status: var EditorStatus,
status.searchNextOccurrenceReversely(word)
elif key == ord('f'):
let secondKey = commands[1]
- currentBufStatus.searchOneCharactorToEndOfLine(
- currentMainWindowNode,
- secondKey)
+ let pos =
+ currentBufStatus.searchOneCharacterToEndOfLine(
+ currentMainWindowNode,
+ secondKey)
+ if pos != -1:
+ currentMainWindowNode.currentColumn = pos
+ elif key == ord('t'):
+ let secondKey = commands[1]
+ let pos =
+ currentBufStatus.searchOneCharacterToEndOfLine(
+ currentMainWindowNode,
+ secondKey)
+ if pos != -1:
+ currentMainWindowNode.currentColumn = pos - 1
elif key == ord('F'):
let secondKey = commands[1]
- currentBufStatus.searchOneCharactorToBeginOfLine(
- currentMainWindowNode,
- secondKey)
+ let pos =
+ currentBufStatus.searchOneCharacterToBeginOfLine(
+ currentMainWindowNode,
+ secondKey)
+ if pos != -1:
+ currentMainWindowNode.currentColumn = pos
+ elif key == ord('T'):
+ let secondKey = commands[1]
+ let pos =
+ currentBufStatus.searchOneCharacterToBeginOfLine(
+ currentMainWindowNode,
+ secondKey)
+ if pos != -1:
+ currentMainWindowNode.currentColumn = pos + 1
elif key == ord('R'):
- status.changeMode(Mode.replace)
+ status.changeModeToReplaceMode
elif key == ord('i'):
- status.changeMode(Mode.insert)
+ status.changeModeToInsertMode
elif key == ord('I'):
- currentBufStatus.moveToFirstNonBlankOfLine(currentMainWindowNode)
- status.changeMode(Mode.insert)
+ status.moveToFirstNonBlankOfLineAndEnterInsertMode
elif key == ord('v'):
- status.changeMode(Mode.visual)
+ status.changeModeToVisualMode
elif key == ord('a'):
status.enterInsertModeAfterCursor
elif key == ord('A'):
- let lineLen = currentBufStatus.buffer[currentMainWindowNode.currentLine].len
- currentMainWindowNode.currentColumn = lineLen
- status.changeMode(Mode.insert)
+ status.moveToEndOfLineAndEnterInsertMode
elif key == ord('u'):
status.bufStatus[currentBufferIndex].undo(currentMainWindowNode)
elif isControlR(key):
@@ -1121,15 +1396,16 @@ proc isNormalModeCommand(command: seq[Rune]): InputState =
if command.len == 1:
result = InputState.Continue
elif command.len == 2:
- if command[1] == ord('i'):
+ if command[1] == ord('i') or
+ command[1] == ord('f'):
result = InputState.Continue
elif command[1] == ord('c') or command[1] == ('l'):
result = InputState.Valid
elif command.len == 3:
- if command[1] == ord('i'):
- if isParen(command[2]) or
- command[2] == ord('w'):
- result = InputState.Valid
+ if command[1] == ord('f') or
+ (command[1] == ord('i') and
+ (isParen(command[2]) or command[2] == ord('w'))):
+ result = InputState.Valid
elif command[0] == ord('d'):
if command.len == 1:
@@ -1163,6 +1439,11 @@ proc isNormalModeCommand(command: seq[Rune]): InputState =
command[1] == ord('}') or
command[1] == ord('l'):
result = InputState.Valid
+ elif command == "yt".ru:
+ result = InputState.Continue
+ elif command.len == 3:
+ if command[0 .. 1] == "yt".ru:
+ result = InputState.Valid
elif command[0] == ord('='):
if command.len == 1:
@@ -1182,12 +1463,24 @@ proc isNormalModeCommand(command: seq[Rune]): InputState =
elif command.len == 2:
result = InputState.Valid
+ elif command[0] == ord('t'):
+ if command.len == 1:
+ result = InputState.Continue
+ elif command.len == 2:
+ result = InputState.Valid
+
elif command[0] == ord('F'):
if command.len == 1:
result = InputState.Continue
elif command.len == 2:
result = InputState.Valid
+ elif command[0] == ord('T'):
+ if command.len == 1:
+ result = InputState.Continue
+ elif command.len == 2:
+ result = InputState.Valid
+
elif command[0] == ord('Z'):
if command.len == 1:
result = InputState.Continue
@@ -1205,7 +1498,7 @@ proc isNormalModeCommand(command: seq[Rune]): InputState =
elif command[0] == ('\\'):
if command.len == 1:
result = InputState.Continue
- if command[1] == ord('r'):
+ elif command[1] == ord('r'):
result = InputState.Valid
elif command[0] == ord('"'):
diff --git a/src/moepkg/platform.nim b/src/moepkg/platform.nim
index 91463c3a5..4853ba2da 100644
--- a/src/moepkg/platform.nim
+++ b/src/moepkg/platform.nim
@@ -1,7 +1,7 @@
-import osproc, strutils
+import std/[osproc, strutils]
type Platforms* = enum
- linux, wsl, mac, other
+ linux, wsl, mac, freebsd, openbsd, other
proc initPlatform(): Platforms =
if defined linux:
@@ -10,6 +10,10 @@ proc initPlatform(): Platforms =
else: result = Platforms.linux
elif defined macosx:
result = Platforms.mac
+ elif defined freebsd:
+ result = Platforms.freebsd
+ elif defined openbsd:
+ result = Platforms.openbsd
else:
result = Platforms.other
diff --git a/src/moepkg/quickrun.nim b/src/moepkg/quickrun.nim
index ed2a55925..6cbf04cdf 100644
--- a/src/moepkg/quickrun.nim
+++ b/src/moepkg/quickrun.nim
@@ -1,4 +1,4 @@
-import osproc, terminal, times
+import std/[osproc, terminal, times]
import syntax/highlite
import unicodeext, settings, bufferstatus, gapbuffer, messages, ui,
editorstatus, movement, window, fileutils, commandline
diff --git a/src/moepkg/recentfilemode.nim b/src/moepkg/recentfilemode.nim
index fb54fbd0f..9d8ef6732 100644
--- a/src/moepkg/recentfilemode.nim
+++ b/src/moepkg/recentfilemode.nim
@@ -1,4 +1,4 @@
-import os, re, terminal
+import std/[os, re, terminal]
import editorstatus, ui, unicodeext, bufferstatus, movement, gapbuffer,
messages, window
diff --git a/src/moepkg/register.nim b/src/moepkg/register.nim
index f84393750..1cea957fb 100644
--- a/src/moepkg/register.nim
+++ b/src/moepkg/register.nim
@@ -1,4 +1,4 @@
-import options, strutils, unicode
+import std/[options, strutils, unicode]
import independentutils, clipboard, settings
type Register* = object
diff --git a/src/moepkg/replacemode.nim b/src/moepkg/replacemode.nim
index 4f5494a3d..97f252fda 100644
--- a/src/moepkg/replacemode.nim
+++ b/src/moepkg/replacemode.nim
@@ -1,4 +1,4 @@
-import terminal, times, unicode
+import std/[terminal, times, unicode]
import editorstatus, ui, movement, editor, bufferstatus, gapbuffer,
window, settings
diff --git a/src/moepkg/search.nim b/src/moepkg/search.nim
index 5db0bd6bf..37286fefe 100644
--- a/src/moepkg/search.nim
+++ b/src/moepkg/search.nim
@@ -1,4 +1,4 @@
-import system, terminal, strutils
+import std/[terminal, strutils]
import editorstatus, gapbuffer, commandview, movement, commandline, unicodeext
type
diff --git a/src/moepkg/settings.nim b/src/moepkg/settings.nim
index 3d5faea53..a9d1f149b 100644
--- a/src/moepkg/settings.nim
+++ b/src/moepkg/settings.nim
@@ -1,13 +1,9 @@
-import parsetoml, os, json, macros, times, options, strformat, osproc, strutils
-from strutils import parseEnum, endsWith, parseInt
-export TomlError
-
-when (NimMajor, NimMinor, NimPatch) > (1, 3, 0):
- # This addresses a breaking change in https://github.com/nim-lang/Nim/pull/14046.
- from strutils import nimIdentNormalize
- export strutils.nimIdentNormalize
-
+import std/[os, json, macros, times, options, strformat, osproc,
+ strutils]
import ui, color, unicodeext, highlight, platform, independentutils
+import parsetoml
+
+export TomlError
type DebugWindowNodeSettings* = object
enable*: bool
@@ -192,6 +188,10 @@ type EditorSettings* = object
highlightSettings*: HighlightSettings
persist*: PersistSettings
+type InvalidItem = object
+ name: string
+ val: string
+
# Warning: inherit from a more precise exception type like ValueError, IOError or OSError.
# If these don't suit, inherit from CatchableError or Defect. [InheritFromException]
type InvalidItemError* = object of ValueError
@@ -950,7 +950,6 @@ proc parseSettingsFile*(settings: TomlValueRef): EditorSettings =
if settings["Standard"].contains("indentationLines"):
result.view.indentationLines = settings["Standard"]["indentationLines"].getbool()
-
if settings.contains("Clipboard"):
if settings["Clipboard"].contains("enable"):
result.clipboard.enable = settings["Clipboard"]["enable"].getbool()
@@ -1652,354 +1651,405 @@ proc parseSettingsFile*(settings: TomlValueRef): EditorSettings =
if result.editorColorTheme == ColorTheme.vscode:
result.editorColorTheme = loadVSCodeTheme()
-proc validateTomlConfig(toml: TomlValueRef): Option[string] =
- template validateStandardTable() =
- for item in json["Standard"].pairs:
- case item.key:
- of "theme":
- var correctValue = false
- if item.val["value"].getStr == "vscode":
- correctValue = true
- else:
- for theme in ColorTheme:
- if $theme == item.val["value"].getStr:
- correctValue = true
- if not correctValue:
- return some($item)
- of "number",
- "currentNumber",
- "cursorLine",
- "statusLine",
- "tabLine",
- "syntax",
- "indentationLines",
- "autoCloseParen",
- "autoIndent",
- "ignorecase",
- "smartcase",
- "disableChangeCursor",
- "autoSave",
- "liveReloadOfConf",
- "incrementalSearch",
- "popUpWindowInExmode",
- "autoDeleteParen",
- "smoothScroll":
- if not (item.val["type"].getStr == "bool"):
- return some($item)
- of "tabStop", "autoSaveInterval", "smoothScrollSpeed":
- if not (item.val["type"].getStr == "integer" and
- parseInt(item.val["value"].getStr) > 0): return some($item)
- of "defaultCursor",
- "normalModeCursor",
- "insertModeCursor":
- let val = item.val["value"].getStr
- var correctValue = false
- for cursorType in CursorType:
- if val == $cursorType:
- correctValue = true
- break
-
- if not correctValue:
- return some($item)
+proc validateStandardTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "theme":
+ var correctValue = false
+ if val.getStr == "vscode":
+ correctValue = true
else:
- return some($item)
-
- template validateClipboardTable() =
- for item in json["Clipboard"].pairs:
- case item.key:
- of "enable":
- if not (item.val["type"].getStr == "bool"):
- return some($item)
- of "toolOnLinux":
- if not (item.val["type"].getStr == "string"):
- return some($item)
- else:
- return some($item)
-
- template validateTabLineTable() =
- for item in json["TabLine"].pairs:
- case item.key:
- of "allBuffer":
- if not (item.val["type"].getStr == "bool"):
- return some($item)
- else:
- return some($item)
-
- template validateStatusLineTable() =
- for item in json["StatusLine"].pairs:
- case item.key:
- of "multipleStatusLine",
- "merge",
- "mode",
- "filename",
- "chanedMark",
- "line",
- "column",
- "encoding",
- "language",
- "directory",
- "gitbranchName",
- "showGitInactive",
- "showModeInactive":
- if not (item.val["type"].getStr == "bool"):
- return some($item)
- else:
- return some($item)
-
- template validateBuildOnSaveTable() =
- for item in json["BuildOnSave"].pairs:
- case item.key:
- of "enable":
- if not (item.val["type"].getStr == "bool"):
- return some($item)
- of "workspaceRoot",
- "command":
- if not (item.val["type"].getStr == "string"):
- return some($item)
- else:
- return some($item)
-
- template validateHighlightTable() =
- for item in json["Highlight"].pairs:
- case item.key:
- of "reservedWord":
- if item.val["type"].getStr == "array":
- for word in item.val["value"]:
- if word["type"].getStr != "string":
- return some($item)
- of "currentLine",
- "fullWidthSpace",
- "trailingSpaces",
- "replaceText",
- "pairOfParen",
- "currentWord":
- if not (item.val["type"].getStr == "bool"):
- return some($item)
- else:
- return some($item)
-
- template validateAutoBackupTable() =
- for item in json["AutoBackup"].pairs:
- case item.key:
- of "enable", "showMessages":
- if item.val["type"].getStr != "bool":
- return some($item)
- of "idleTime",
- "interval":
- if item.val["type"].getStr != "integer":
- return some($item)
- of "backupDir":
- if item.val["type"].getStr != "string":
- return some($item)
- of "dirToExclude":
- if item.val["type"].getStr == "array":
- for word in item.val["value"]:
- if word["type"].getStr != "string":
- return some($item)
- else:
- return some($item)
-
- template validateQuickRunTable() =
- for item in json["QuickRun"].pairs:
- case item.key:
- of "saveBufferWhenQuickRun":
- if item.val["type"].getStr != "bool":
- return some($item)
- of "command",
- "nimAdvancedCommand",
- "ClangOptions",
- "CppOptions",
- "NimOptions",
- "shOptions",
- "bashOptions":
- if item.val["type"].getStr != "string":
- return some($item)
- of "timeout":
- if item.val["type"].getStr != "integer":
- return some($item)
- else:
- return some($item)
-
- template validateNotificationTable() =
- for item in json["Notification"].pairs:
- case item.key:
- of "screenNotifications",
- "logNotifications",
- "autoBackupScreenNotify",
- "autoBackupLogNotify",
- "autoSaveScreenNotify",
- "autoSaveLogNotify",
- "yankScreenNotify",
- "yankLogNotify",
- "deleteScreenNotify",
- "deleteLogNotify",
- "saveScreenNotify",
- "saveLogNotify",
- "quickRunScreenNotify",
- "quickRunLogNotify",
- "buildOnSaveScreenNotify",
- "buildOnSaveLogNotify",
- "filerScreenNotify",
- "filerLogNotify",
- "restoreScreenNotify",
- "restoreLogNotify":
- if item.val["type"].getStr != "bool":
- return some($item)
- else:
- return some($item)
-
- template validateFilerTable() =
- for item in json["Filer"].pairs:
- case item.key:
- of "showIcons":
- if item.val["type"].getStr != "bool":
- return some($item)
- else:
- return some($item)
+ for theme in ColorTheme:
+ if $theme == val.getStr:
+ correctValue = true
+ if not correctValue:
+ return some(InvalidItem(name: $key, val: $val))
+ of "number",
+ "currentNumber",
+ "cursorLine",
+ "statusLine",
+ "tabLine",
+ "syntax",
+ "indentationLines",
+ "autoCloseParen",
+ "autoIndent",
+ "ignorecase",
+ "smartcase",
+ "disableChangeCursor",
+ "autoSave",
+ "liveReloadOfConf",
+ "incrementalSearch",
+ "popUpWindowInExmode",
+ "autoDeleteParen",
+ "systemClipboard",
+ "smoothScroll":
+ if not (val.kind == TomlValueKind.Bool):
+ return some(InvalidItem(name: $key, val: $val))
+ of "tabStop", "autoSaveInterval", "smoothScrollSpeed":
+ if not (val.kind == TomlValueKind.Int and val.getInt > 0):
+ return some(InvalidItem(name: $key, val: $val))
+ of "defaultCursor",
+ "normalModeCursor",
+ "insertModeCursor":
+ let val = val.getStr
+ var correctValue = false
+ for cursorType in CursorType:
+ if val == $cursorType:
+ correctValue = true
+ break
+ if not correctValue:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateClipboardTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "enable":
+ if not (val.kind == TomlValueKind.Bool):
+ return some(InvalidItem(name: $key, val: $val))
+ of "toolOnLinux":
+ if not (
+ (val.kind == TomlValueKind.String) and
+ (val.getStr == "none" or
+ val.getStr == "xclip" or
+ val.getStr == "xsel" or
+ val.getStr == "wl-clipboard")): return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateTabLineTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "allBuffer":
+ if not (val.kind == TomlValueKind.Bool):
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateBuildOnSaveTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "enable":
+ if not (val.kind == TomlValueKind.Bool):
+ return some(InvalidItem(name: $key, val: $val))
+ of "workspaceRoot",
+ "command":
+ if not (val.kind == TomlValueKind.String):
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateStatusLineTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "multipleStatusLine",
+ "merge",
+ "mode",
+ "filename",
+ "chanedMark",
+ "line",
+ "column",
+ "encoding",
+ "language",
+ "directory",
+ "gitbranchName",
+ "showGitInactive",
+ "showModeInactive":
+ if not (val.kind == TomlValueKind.Bool):
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateWorkSpaceTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "workSpaceLine":
+ if not (val.kind == TomlValueKind.Bool):
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateHighlightTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "reservedWord":
+ if val.kind == TomlValueKind.Array:
+ for key, val in val.getTable:
+ if val.kind != TomlValueKind.String:
+ return some(InvalidItem(name: $key, val: $val))
+ of "currentLine",
+ "fullWidthSpace",
+ "trailingSpaces",
+ "replaceText",
+ "pairOfParen",
+ "currentWord":
+ if not (val.kind == TomlValueKind.Bool):
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateAutoBackupTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "enable", "showMessages":
+ if val.kind != TomlValueKind.Bool:
+ return some(InvalidItem(name: $key, val: $val))
+ of "idleTime",
+ "interval":
+ if val.kind != TomlValueKind.Int:
+ return some(InvalidItem(name: $key, val: $val))
+ of "backupDir":
+ if val.kind != TomlValueKind.String:
+ return some(InvalidItem(name: $key, val: $val))
+ of "dirToExclude":
+ if val.kind != TomlValueKind.Array:
+ for item in val.getElems:
+ if item.kind != TomlValueKind.String:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateQuickRunTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "saveBufferWhenQuickRun":
+ if val.kind != TomlValueKind.Bool:
+ return some(InvalidItem(name: $key, val: $val))
+ of "command",
+ "nimAdvancedCommand",
+ "ClangOptions",
+ "CppOptions",
+ "NimOptions",
+ "shOptions",
+ "bashOptions":
+ if val.kind != TomlValueKind.String:
+ return some(InvalidItem(name: $key, val: $val))
+ of "timeout":
+ if val.kind != TomlValueKind.Int:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateNotificationTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "screenNotifications",
+ "logNotifications",
+ "autoBackupScreenNotify",
+ "autoBackupLogNotify",
+ "autoSaveScreenNotify",
+ "autoSaveLogNotify",
+ "yankScreenNotify",
+ "yankLogNotify",
+ "deleteScreenNotify",
+ "deleteLogNotify",
+ "saveScreenNotify",
+ "saveLogNotify",
+ "workspaceScreenNotify",
+ "workspaceLogNotify",
+ "quickRunScreenNotify",
+ "quickRunLogNotify",
+ "buildOnSaveScreenNotify",
+ "buildOnSaveLogNotify",
+ "filerScreenNotify",
+ "filerLogNotify",
+ "restoreScreenNotify",
+ "restoreLogNotify":
+ if val.kind != TomlValueKind.Bool:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateFilerTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "showIcons":
+ if val.kind != TomlValueKind.Bool:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
- template validateAutocompleteTable() =
- for item in json["Autocomplete"].pairs:
- case item.key:
+proc validateAutocompleteTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
of "enable":
- if item.val["type"].getStr != "bool":
- return some($item)
+ if val.kind != TomlValueKind.Bool:
+ return some(InvalidItem(name: $key, val: $val))
else:
- return some($item)
-
- template validatePersistTable() =
- for item in json["Persist"].pairs:
- case item.key:
- of "exCommand", "search", "cursorPosition":
- if item.val["type"].getStr != "bool":
- return some($item)
- else:
- return some($item)
-
- template validateDebugTable() =
- for item in json["Debug"].pairs:
- case item.key:
- # Check [Debug.WindowNode]
- of "WindowNode":
- for item in json["Debug"]["WindowNode"].pairs:
- case item.key:
- of "enable",
- "currentWindow",
- "index",
- "windowIndex",
- "bufferIndex",
- "parentIndex",
- "childLen",
- "splitType",
- "haveCursesWin",
- "y",
- "x",
- "h",
- "w",
- "currentLine",
- "currentColumn",
- "expandedColumn",
- "cursor":
- if item.val["type"].getStr != "bool":
- return some($item)
- else:
- return some($item)
- # Check [Debug.EditorView]
- of "EditorView":
- for item in json["Debug"]["EditorView"].pairs:
- case item.key:
- of "enable",
- "widthOfLineNum",
- "height",
- "width",
- "originalLine",
- "start",
- "length":
- if item.val["type"].getStr != "bool":
- return some($item)
- else:
- return some($item)
- # Check [Debug.BufferStatus]
- of "BufferStatus":
- for item in json["Debug"]["BufferStatus"].pairs:
- case item.key:
- of "enable",
- "bufferIndex",
- "path",
- "openDir",
- "currentMode",
- "prevMode",
- "language",
- "encoding",
- "countChange",
- "cmdLoop",
- "lastSaveTime",
- "bufferLen":
- if item.val["type"].getStr != "bool":
- return some($item)
- else:
- return some($item)
- else:
- return some($item)
-
- template validateThemeTable() =
- let editorColors = ColorThemeTable[ColorTheme.config].EditorColor
- for item in json["Theme"].pairs:
- case item.key:
- of "baseTheme":
- var correctKey = false
- for theme in ColorTheme:
- if $theme == item.val["value"].getStr:
- correctKey = true
- if not correctKey: return some($item)
- else:
- # Check color names
- var correctKey = false
- for field, val in editorColors.fieldPairs:
- if item.key == field and
- item.val["type"].getStr == "string":
- for color in Color:
- if item.val["value"].getStr == $color:
- correctKey = true
- break
- if correctKey: break
- if not correctKey:
- return some($item)
-
- let json = toml.toJson
-
- for table in json.keys:
- case table:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validatePersistTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "exCommand", "search", "cursorPosition":
+ if val.kind != TomlValueKind.Bool:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateDebugTable(table: TomlValueRef): Option[InvalidItem] =
+ for key, val in table.getTable:
+ case key:
+ of "WorkSpace":
+ # Check [Debug.WorkSpace]
+ for key,val in table["WorkSpace"].getTable:
+ case key:
+ of "enable",
+ "numOfWorkSpaces",
+ "currentWorkSpaceIndex":
+ if val.kind != TomlValueKind.Bool:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+ # Check [Debug.WindowNode]
+ of "WindowNode":
+ for key, val in table["WindowNode"].getTable:
+ case key:
+ of "enable",
+ "currentWindow",
+ "index",
+ "windowIndex",
+ "bufferIndex",
+ "parentIndex",
+ "childLen",
+ "splitType",
+ "haveCursesWin",
+ "y",
+ "x",
+ "h",
+ "w",
+ "currentLine",
+ "currentColumn",
+ "expandedColumn",
+ "cursor":
+ if val.kind != TomlValueKind.Bool:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+ # Check [Debug.EditorView]
+ of "EditorView":
+ for key, val in table["EditorView"].getTable:
+ case key:
+ of "enable",
+ "widthOfLineNum",
+ "height",
+ "width",
+ "originalLine",
+ "start",
+ "length":
+ if val.kind != TomlValueKind.Bool:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+ # Check [Debug.BufferStatus]
+ of "BufferStatus":
+ for key, val in table["BufferStatus"].getTable:
+ case key:
+ of "enable",
+ "bufferIndex",
+ "path",
+ "openDir",
+ "currentMode",
+ "prevMode",
+ "language",
+ "encoding",
+ "countChange",
+ "cmdLoop",
+ "lastSaveTime",
+ "bufferLen":
+ if val.kind != TomlValueKind.Bool:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateThemeTable(table: TomlValueRef): Option[InvalidItem] =
+ let editorColors = ColorThemeTable[ColorTheme.config].EditorColor
+ for key, val in table.getTable:
+ case key:
+ of "baseTheme":
+ var correctKey = false
+ for theme in ColorTheme:
+ if $theme == val.getStr:
+ correctKey = true
+ if not correctKey: return some(InvalidItem(name: $key, val: $val))
+ else:
+ # Check color names
+ var correctKey = false
+ for field, fieldVal in editorColors.fieldPairs:
+ if key == field and
+ val.kind == TomlValueKind.String:
+ for color in Color:
+ if val.getStr == $color:
+ correctKey = true
+ break
+ if correctKey: break
+ if not correctKey:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc validateTomlConfig(toml: TomlValueRef): Option[InvalidItem] =
+ for key, val in toml.getTable:
+ case key:
of "Standard":
- validateStandardTable()
+ let r = validateStandardTable(val)
+ if r.isSome: return r
of "Clipboard":
- validateClipboardTable()
+ let r = validateClipboardTable(val)
+ if r.isSome: return r
of "TabLine":
- validateTabLineTable()
+ let r = validateTabLineTable(val)
+ if r.isSome: return r
of "StatusLine":
- validateStatusLineTable()
+ let r = validateStatusLineTable(val)
+ if r.isSome: return r
of "BuildOnSave":
- validateBuildOnSaveTable()
+ let r = validateBuildOnSaveTable(val)
+ if r.isSome: return r
+ of "WorkSpace":
+ let r = validateWorkSpaceTable(val)
+ if r.isSome: return r
of "Highlight":
- validateHighlightTable()
+ let r = validateHighlightTable(val)
+ if r.isSome: return r
of "AutoBackup":
- validateAutoBackupTable()
+ let r = validateAutoBackupTable(val)
+ if r.isSome: return r
of "QuickRun":
- validateQuickRunTable()
+ let r = validateQuickRunTable(val)
+ if r.isSome: return r
of "Notification":
- validateNotificationTable()
+ let r = validateNotificationTable(val)
+ if r.isSome: return r
of "Filer":
- validateFilerTable()
+ let r = validateFilerTable(val)
+ if r.isSome: return r
of "Theme":
- validateThemeTable()
+ let r = validateThemeTable(val)
+ if r.isSome: return r
of "Autocomplete":
- validateAutocompleteTable()
- of "Debug":
- validateDebugTable()
+ let r = validateAutocompleteTable(val)
+ if r.isSome: return r
of "Persist":
- validatePersistTable()
- else: discard
+ let r = validatePersistTable(val)
+ if r.isSome: return r
+ of "Debug":
+ let r = validateDebugTable(val)
+ if r.isSome: return r
+ else:
+ return some(InvalidItem(name: $key, val: $val))
+
+proc toValidateErrorMessage(invalidItem: InvalidItem): string =
+ # Remove '\n'
+ let lines = invalidItem.val.splitLines
+
+ var val = ""
+ for i in 0 ..< lines.len:
+ val &= lines[i]
+ if i < lines.high - 1: val &= " "
- return none(string)
+ result = fmt"(name: {invalidItem.name}, val: {val})"
proc loadSettingFile*(): EditorSettings =
let filename = getConfigDir() / "moe" / "moerc.toml"
@@ -2011,8 +2061,9 @@ proc loadSettingFile*(): EditorSettings =
toml = parsetoml.parseFile(filename)
invalidItem = toml.validateTomlConfig
- if invalidItem != none(string):
- raise newException(InvalidItemError, $invalidItem)
+ if invalidItem != none(InvalidItem):
+ let errorMessage = toValidateErrorMessage(invalidItem.get)
+ raise newException(InvalidItemError, $errorMessage)
else:
return parseSettingsFile(toml)
@@ -2068,8 +2119,8 @@ proc generateTomlConfigStr*(settings: EditorSettings): string =
result.addLine ""
- result.addLine fmt "[StatusBar]"
- result.addLine fmt "multipleStatusBar = {$settings.statusLine.multipleStatusLine}"
+ result.addLine fmt "[StatusLine]"
+ result.addLine fmt "multipleStatusLine = {$settings.statusLine.multipleStatusLine}"
result.addLine fmt "merge = {$settings.statusLine.merge }"
result.addLine fmt "mode = {$settings.statusLine.mode }"
result.addLine fmt "filename = {$settings.statusLine.filename}"
diff --git a/src/moepkg/statusline.nim b/src/moepkg/statusline.nim
index bbc68a28e..dd6807ef4 100644
--- a/src/moepkg/statusline.nim
+++ b/src/moepkg/statusline.nim
@@ -1,6 +1,6 @@
-import ui, strutils, strformat, os, osproc
+import std/[strutils, strformat, os, osproc]
import syntax/highlite
-import bufferstatus, color, unicodeext, settings, window, gapbuffer
+import ui, bufferstatus, color, unicodeext, settings, window, gapbuffer
type StatusLine* = object
window*: Window
diff --git a/src/moepkg/suggestionwindow.nim b/src/moepkg/suggestionwindow.nim
index c912b036e..92b80dd8c 100644
--- a/src/moepkg/suggestionwindow.nim
+++ b/src/moepkg/suggestionwindow.nim
@@ -1,4 +1,4 @@
-import critbits, unicode, sugar, options, sequtils, unicode
+import std/[critbits, sugar, options, sequtils, unicode]
import ui, window, generalautocomplete, bufferstatus, gapbuffer, color,
editorstatus
diff --git a/src/moepkg/syntax/highlite.nim b/src/moepkg/syntax/highlite.nim
index 319a50c9a..7284b18d9 100644
--- a/src/moepkg/syntax/highlite.nim
+++ b/src/moepkg/syntax/highlite.nim
@@ -65,8 +65,8 @@
##
import
- strutils
-from algorithm import binarySearch
+ std/strutils
+from std/algorithm import binarySearch
type
TokenClass* = enum
diff --git a/src/moepkg/syntax/syntaxnim.nim b/src/moepkg/syntax/syntaxnim.nim
index 466aec0dc..888368a4b 100644
--- a/src/moepkg/syntax/syntaxnim.nim
+++ b/src/moepkg/syntax/syntaxnim.nim
@@ -31,8 +31,8 @@
# distribution, for details about the copyright.
#
-import strutils
-from algorithm import binarySearch
+import std/strutils
+from std/algorithm import binarySearch
import highlite
diff --git a/src/moepkg/tabline.nim b/src/moepkg/tabline.nim
index db6fc9f34..daad5ba48 100644
--- a/src/moepkg/tabline.nim
+++ b/src/moepkg/tabline.nim
@@ -1,4 +1,4 @@
-import strutils, terminal, unicode
+import std/[strutils, terminal, unicode]
import ui, window, color, bufferstatus, independentutils
proc writeTab*(tabWin: var Window,
diff --git a/src/moepkg/ui.nim b/src/moepkg/ui.nim
index f5a9b9255..23b9a980d 100644
--- a/src/moepkg/ui.nim
+++ b/src/moepkg/ui.nim
@@ -1,8 +1,8 @@
-import strformat, osproc, strutils
+import std/[strformat, osproc, strutils]
when not defined unitTest:
- import posix
+ import std/posix
-from os import execShellCmd
+from std/os import execShellCmd
import ncurses
import unicodeext, color
@@ -162,7 +162,7 @@ proc append*(win: var Window,
# Not write when running unit tests
when not defined unitTest:
win.cursesWindow.wattron(cint(ncurses.COLOR_PAIR(ord(color))))
- mvwaddstr(win.cursesWindow, cint(win.y), cint(win.x), $str)
+ mvwaddstr(win.cursesWindow, cint(win.y), cint(win.x), str)
win.x += str.toRunes.width
diff --git a/src/moepkg/undoredostack.nim b/src/moepkg/undoredostack.nim
index 941323898..5f63ddcde 100644
--- a/src/moepkg/undoredostack.nim
+++ b/src/moepkg/undoredostack.nim
@@ -1,4 +1,4 @@
-import sequtils, tables
+import std/[sequtils, tables]
type
CommandKind = enum
diff --git a/src/moepkg/unicodeext.nim b/src/moepkg/unicodeext.nim
index a6980e6ee..ee0020d78 100644
--- a/src/moepkg/unicodeext.nim
+++ b/src/moepkg/unicodeext.nim
@@ -1,4 +1,4 @@
-import unicode, strutils, sequtils, strutils, strformat
+import std/[unicode, sequtils, strutils, strformat, os]
import unicodedb/widths
import gapbuffer
export unicode
@@ -377,7 +377,6 @@ proc toggleCase*(ch: Rune): Rune =
result = result.toUpper()
return result
-from os import `/`
proc `/`*(runes1, runes2: seq[Rune]): seq[Rune] {.inline.} =
toRunes($runes1 / $runes2)
@@ -424,6 +423,7 @@ proc encodeUTF8*(r: Rune): seq[uint32] =
result.add mbLead or i shl 6
result.add mbLead or i and mbMask
-from os import absolutePath
proc absolutePath*(runes: seq[Rune]): seq[Rune] {.inline.} =
- absolutePath($runes).ru
+ result = absolutePath($runes).ru
+ if result.len > 0 and dirExists($runes) and result[^1] != ru '/':
+ result &= ru "/"
diff --git a/src/moepkg/visualmode.nim b/src/moepkg/visualmode.nim
index fecd976d3..b8177339c 100644
--- a/src/moepkg/visualmode.nim
+++ b/src/moepkg/visualmode.nim
@@ -1,6 +1,6 @@
-import terminal, strutils, sequtils, times
+import std/[terminal, strutils, sequtils, times]
import editorstatus, ui, gapbuffer, unicodeext, window, movement, editor,
- bufferstatus, settings, register
+ bufferstatus, settings, register, messages, commandline
proc initSelectArea(startLine, startColumn: int): SelectArea =
result.startLine = startLine
@@ -78,7 +78,12 @@ proc deleteBuffer(bufStatus: var BufferStatus,
registers: var Registers,
windowNode: WindowNode,
area: SelectArea,
- settings: EditorSettings) =
+ settings: EditorSettings,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
if bufStatus.buffer.len == 1 and
bufStatus.buffer[windowNode.currentLine].len < 1: return
@@ -116,16 +121,24 @@ proc deleteBuffer(bufStatus: var BufferStatus,
elif area.startColumn > 0:
area.startColumn - 1
else: 0
+
windowNode.currentColumn = column
windowNode.expandedColumn = column
inc(bufStatus.countChange)
+ bufStatus.isUpdate = true
+
proc deleteBufferBlock(bufStatus: var BufferStatus,
registers: var Registers,
windowNode: WindowNode,
area: SelectArea,
- settings: EditorSettings) =
+ settings: EditorSettings,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
if bufStatus.buffer.len == 1 and
bufStatus.buffer[windowNode.currentLine].len < 1: return
@@ -148,12 +161,20 @@ proc deleteBufferBlock(bufStatus: var BufferStatus,
windowNode.currentLine = min(area.startLine, bufStatus.buffer.high)
windowNode.currentColumn = area.startColumn
+
inc(bufStatus.countChange)
+ bufStatus.isUpdate = true
+
proc addIndent(bufStatus: var BufferStatus,
windowNode: WindowNode,
area: SelectArea,
- tabStop: int) =
+ tabStop: int,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
windowNode.currentLine = area.startLine
for i in area.startLine .. area.endLine:
@@ -165,7 +186,12 @@ proc addIndent(bufStatus: var BufferStatus,
proc deleteIndent(bufStatus: var BufferStatus,
windowNode: WindowNode,
area: SelectArea,
- tabStop: int) =
+ tabStop: int,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
windowNode.currentLine = area.startLine
for i in area.startLine .. area.endLine:
@@ -174,7 +200,15 @@ proc deleteIndent(bufStatus: var BufferStatus,
windowNode.currentLine = area.startLine
-proc insertIndent(bufStatus: var BufferStatus, area: SelectArea, tabStop: int) =
+proc insertIndent(bufStatus: var BufferStatus,
+ area: SelectArea,
+ tabStop: int,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
+
for i in area.startLine .. area.endLine:
let oldLine = bufStatus.buffer[i]
var newLine = bufStatus.buffer[i]
@@ -183,7 +217,15 @@ proc insertIndent(bufStatus: var BufferStatus, area: SelectArea, tabStop: int) =
bufStatus.buffer[i].high))
if oldLine != newLine: bufStatus.buffer[i] = newLine
-proc replaceCharacter(bufStatus: var BufferStatus, area: SelectArea, ch: Rune) =
+proc replaceCharacter(bufStatus: var BufferStatus,
+ area: SelectArea,
+ ch: Rune,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
+
for i in area.startLine .. area.endLine:
let oldLine = bufStatus.buffer[i]
var newLine = bufStatus.buffer[i]
@@ -201,7 +243,12 @@ proc replaceCharacter(bufStatus: var BufferStatus, area: SelectArea, ch: Rune) =
proc replaceCharacterBlock(bufStatus: var BufferStatus,
area: SelectArea,
- ch: Rune) =
+ ch: Rune,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
for i in area.startLine .. area.endLine:
let oldLine = bufStatus.buffer[i]
@@ -212,13 +259,25 @@ proc replaceCharacterBlock(bufStatus: var BufferStatus,
proc joinLines(bufStatus: var BufferStatus,
windowNode: WindowNode,
- area: SelectArea) =
+ area: SelectArea,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
for i in area.startLine .. area.endLine:
windowNode.currentLine = area.startLine
bufStatus.joinLine(windowNode)
-proc toLowerString(bufStatus: var BufferStatus, area: SelectArea) =
+proc toLowerString(bufStatus: var BufferStatus,
+ area: SelectArea,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
+
for i in area.startLine .. area.endLine:
let oldLine = bufStatus.buffer[i]
var newLine = bufStatus.buffer[i]
@@ -237,7 +296,14 @@ proc toLowerString(bufStatus: var BufferStatus, area: SelectArea) =
inc(bufStatus.countChange)
-proc toLowerStringBlock(bufStatus: var BufferStatus, area: SelectArea) =
+proc toLowerStringBlock(bufStatus: var BufferStatus,
+ area: SelectArea,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
+
for i in area.startLine .. area.endLine:
let oldLine = bufStatus.buffer[i]
var newLine = bufStatus.buffer[i]
@@ -245,7 +311,14 @@ proc toLowerStringBlock(bufStatus: var BufferStatus, area: SelectArea) =
newLine[j] = oldLine[j].toLower
if oldLine != newLine: bufStatus.buffer[i] = newLine
-proc toUpperString(bufStatus: var BufferStatus, area: SelectArea) =
+proc toUpperString(bufStatus: var BufferStatus,
+ area: SelectArea,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
+
for i in area.startLine .. area.endLine:
let oldLine = bufStatus.buffer[i]
var newLine = bufStatus.buffer[i]
@@ -264,7 +337,14 @@ proc toUpperString(bufStatus: var BufferStatus, area: SelectArea) =
inc(bufStatus.countChange)
-proc toUpperStringBlock(bufStatus: var BufferStatus, area: SelectArea) =
+proc toUpperStringBlock(bufStatus: var BufferStatus,
+ area: SelectArea,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
+
for i in area.startLine .. area.endLine:
let oldLine = bufStatus.buffer[i]
var newLine = bufStatus.buffer[i]
@@ -292,8 +372,9 @@ proc getInsertBuffer(status: var Editorstatus): seq[Rune] =
status.settings.tabStop)
break
elif isDcKey(key):
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
break
elif isBackspaceKey(key):
@@ -316,12 +397,25 @@ proc getInsertBuffer(status: var Editorstatus): seq[Rune] =
status.settings.autoCloseParen,
key)
+proc enterInsertMode(status: var EditorStatus) =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ else:
+ currentMainWindowNode.currentLine = currentBufStatus.selectArea.startLine
+ currentMainWindowNode.currentColumn = 0
+ status.changeMode(Mode.insert)
+
proc insertCharBlock(bufStatus: var BufferStatus,
windowNode: var WindowNode,
insertBuffer: seq[Rune],
area: SelectArea,
tabStop: int,
- autoCloseParen: bool) =
+ autoCloseParen: bool,
+ commandLine: var CommandLine) =
+
+ if bufStatus.isReadonly:
+ commandLine.writeReadonlyModeWarning
+ return
if area.startLine == area.endLine: return
@@ -356,35 +450,40 @@ proc visualCommand(status: var EditorStatus, area: var SelectArea, key: Rune) =
currentBufStatus.deleteBuffer(status.registers,
currentMainWindowNode,
area,
- status.settings)
+ status.settings,
+ status.commandLine)
elif key == ord('>'):
currentBufStatus.addIndent(currentMainWindowNode,
area,
- status.settings.tabStop)
+ status.settings.tabStop,
+ status.commandLine)
elif key == ord('<'):
currentBufStatus.deleteIndent(currentMainWindowNode,
area,
- status.settings.tabStop)
+ status.settings.tabStop,
+ status.commandLine)
elif key == ord('J'):
- currentBufStatus.joinLines(currentMainWindowNode, area)
+ currentBufStatus.joinLines(currentMainWindowNode, area, status.commandLine)
elif key == ord('u'):
- currentBufStatus.toLowerString(area)
+ currentBufStatus.toLowerString(area, status.commandLine)
elif key == ord('U'):
- currentBufStatus.toUpperString(area)
+ currentBufStatus.toUpperString(area, status.commandLine)
elif key == ord('r'):
let ch = currentMainWindowNode.getKey
if not isEscKey(ch):
- currentBufStatus.replaceCharacter(area, ch)
+ currentBufStatus.replaceCharacter(area, ch, status.commandLine)
elif key == ord('I'):
- currentMainWindowNode.currentLine = currentBufStatus.selectArea.startLine
- currentMainWindowNode.currentColumn = 0
- status.changeMode(Mode.insert)
+ status.enterInsertMode
else: discard
proc visualBlockCommand(status: var EditorStatus, area: var SelectArea, key: Rune) =
area.swapSelectArea
template insertCharacterMultipleLines() =
+ if currentBufStatus.isReadonly:
+ status.commandLine.writeReadonlyModeWarning
+ return
+
status.changeMode(Mode.insert)
currentMainWindowNode.currentLine = area.startLine
@@ -398,7 +497,8 @@ proc visualBlockCommand(status: var EditorStatus, area: var SelectArea, key: Run
insertBuffer,
area,
status.settings.tabStop,
- status.settings.autoCloseParen)
+ status.settings.autoCloseParen,
+ status.commandLine)
else:
currentMainWindowNode.currentLine = area.startLine
currentMainWindowNode.currentColumn = area.startColumn
@@ -412,22 +512,28 @@ proc visualBlockCommand(status: var EditorStatus, area: var SelectArea, key: Run
currentBufStatus.deleteBufferBlock(status.registers,
currentMainWindowNode,
area,
- status.settings)
+ status.settings,
+ status.commandLine)
elif key == ord('>'):
- currentBufStatus.insertIndent(area, status.settings.tabStop)
+ currentBufStatus.insertIndent(
+ area,
+ status.settings.tabStop,
+ status.commandLine)
elif key == ord('<'):
currentBufStatus.deleteIndent(currentMainWindowNode,
area,
- status.settings.tabStop)
+ status.settings.tabStop,
+ status.commandLine)
elif key == ord('J'):
- currentBufStatus.joinLines(currentMainWindowNode, area)
+ currentBufStatus.joinLines(currentMainWindowNode, area, status.commandLine)
elif key == ord('u'):
- currentBufStatus.toLowerStringBlock(area)
+ currentBufStatus.toLowerStringBlock(area, status.commandLine)
elif key == ord('U'):
- currentBufStatus.toUpperStringBlock(area)
+ currentBufStatus.toUpperStringBlock(area, status.commandLine)
elif key == ord('r'):
let ch = currentMainWindowNode.getKey
- if not isEscKey(ch): currentBufStatus.replaceCharacterBlock(area, ch)
+ if not isEscKey(ch):
+ currentBufStatus.replaceCharacterBlock(area, ch, status.commandLine)
elif key == ord('I'):
insertCharacterMultipleLines()
else: discard
@@ -503,13 +609,16 @@ proc visualMode*(status: var EditorStatus) =
elif key == ord('g'):
if getKey(currentMainWindowNode) == ord('g'):
moveToFirstLine(status)
- elif key == ord('i'):
- currentMainWindowNode.currentLine = currentBufStatus.selectArea.startLine
- status.changeMode(Mode.insert)
+ else:
+ currentMainWindowNode.currentLine = currentBufStatus.selectArea.startLine
+ status.changeMode(Mode.insert)
else:
if isVisualBlockMode(currentBufStatus.mode):
status.visualBlockCommand(currentBufStatus.selectArea, key)
else:
status.visualCommand(currentBufStatus.selectArea, key)
+
status.update
- status.changeMode(Mode.normal)
+
+ if isNormalMode(currentBufStatus.mode, currentBufStatus.prevMode):
+ status.changeMode(Mode.normal)
diff --git a/src/moepkg/window.nim b/src/moepkg/window.nim
index 195490b01..66be9383a 100644
--- a/src/moepkg/window.nim
+++ b/src/moepkg/window.nim
@@ -1,4 +1,4 @@
-import heapqueue, options
+import std/[heapqueue, options]
import ui, editorview, gapbuffer, color, cursor, highlight, unicodeext
# vertical is default
diff --git a/tests/tbackup.nim b/tests/tbackup.nim
index 2217096b7..13d3af5b3 100644
--- a/tests/tbackup.nim
+++ b/tests/tbackup.nim
@@ -1,4 +1,4 @@
-import unittest, times, os
+import std/[unittest, times, os]
import moepkg/unicodeext
include moepkg/backup
diff --git a/tests/tclipboard.nim b/tests/tclipboard.nim
index 48944b445..e70642d94 100644
--- a/tests/tclipboard.nim
+++ b/tests/tclipboard.nim
@@ -1,4 +1,4 @@
-import unittest
+import std/unittest
import moepkg/[settings, unicodeext, register, clipboard]
include moepkg/[platform]
diff --git a/tests/tcommandview.nim b/tests/tcommandview.nim
index ab3e485e8..34639521b 100644
--- a/tests/tcommandview.nim
+++ b/tests/tcommandview.nim
@@ -1,4 +1,4 @@
-import unittest, os, strutils
+import std/[unittest, os, strutils]
import moepkg/[editorstatus, unicodeext]
include moepkg/commandview
diff --git a/tests/tconfigmode.nim b/tests/tconfigmode.nim
index 72c16b2e0..d2fa0b33c 100644
--- a/tests/tconfigmode.nim
+++ b/tests/tconfigmode.nim
@@ -1,4 +1,4 @@
-import unittest, macros, strformat
+import std/[unittest, macros, strformat]
import moepkg/[editorstatus, gapbuffer, bufferstatus, unicodeext]
include moepkg/configmode
diff --git a/tests/tdebugmode.nim b/tests/tdebugmode.nim
index fa0b37676..631992e10 100644
--- a/tests/tdebugmode.nim
+++ b/tests/tdebugmode.nim
@@ -1,4 +1,4 @@
-import unittest, strformat
+import std/[unittest, strformat]
import moepkg/[editorstatus, unicodeext, bufferstatus]
include moepkg/debugmode
diff --git a/tests/teditor.nim b/tests/teditor.nim
index 95706b664..e8737a26a 100644
--- a/tests/teditor.nim
+++ b/tests/teditor.nim
@@ -1,4 +1,4 @@
-import unittest, macros
+import std/[unittest, macros]
import moepkg/register
include moepkg/[editor, editorstatus, ui, platform]
@@ -555,6 +555,9 @@ suite "Editor: keyEnter: Enable autoindent in Nim":
block:
const keyword = "object"
newLineTestInNimCase4(keyword)
+ block:
+ const keyword = "="
+ newLineTestInNimCase4(keyword)
# Generate test code
# Enable autoindent
@@ -597,6 +600,9 @@ suite "Editor: keyEnter: Enable autoindent in Nim":
block:
const keyword = "object"
newLineTestInNimCase5(keyword)
+ block:
+ const keyword = "="
+ newLineTestInNimCase5(keyword)
# Generate test code
# Enable autoindent
@@ -919,6 +925,22 @@ suite "Editor: keyEnter and autoindent in Python":
check currentBufStatus.buffer[0] == ru"if true or"
check currentBufStatus.buffer[1] == ru" "
+ test "Insert a new line in Nim (Fix #1450)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ status.bufStatus[0].buffer = initGapBuffer(@[ru"block:", ru" const a = 0"])
+ currentBufStatus.language = SourceLanguage.langNim
+ status.bufStatus[0].mode = Mode.insert
+ currentMainWindowNode.currentLine = 1
+ currentMainWindowNode.currentColumn = currentBufStatus.buffer[1].len
+
+ const isAutoIndent = true
+ for i in 0 ..< 2:
+ currentBufStatus.keyEnter(currentMainWindowNode,
+ isAutoIndent,
+ status.settings.tabStop)
+
suite "Delete character before cursor":
test "Delete one character":
var status = initEditorStatus()
@@ -1643,7 +1665,7 @@ suite "Editor: Open the blank line below":
# Generate test code
# Enable autoindent
# open the blank line below in Nim
- # When the current line ends with "or", "and", ':', "object".
+ # When the current line ends with "or", "and", ':', "object", '='.
macro openLineBelowTestCase3(keyword: string): untyped =
quote do:
# Generate test title
@@ -1685,6 +1707,9 @@ suite "Editor: Open the blank line below":
block:
const keyword = "object"
openLineBelowTestCase3(keyword)
+ block:
+ const keyword = "="
+ openLineBelowTestCase3(keyword)
# Generate test code
# Enable/Disable autoindent
@@ -1926,7 +1951,7 @@ suite "Editor: Open the blank line abave":
# Generate test code
# Enable autoindent
# open the blank line above in Nim
- # When the current line ends with "or", "and", ':', "object".
+ # When the current line ends with "or", "and", ':', "object", "=".
macro openLineAboveTestCase4(keyword: string): untyped =
quote do:
# Generate test title
@@ -1974,6 +1999,9 @@ suite "Editor: Open the blank line abave":
block:
const keyword = "object"
openLineAboveTestCase4(keyword)
+ block:
+ const keyword = "="
+ openLineAboveTestCase4(keyword)
# Generate test code
# Enable autoindent
@@ -2021,5 +2049,3 @@ suite "Editor: Open the blank line abave":
block:
const keyword = ":"
openLineAboveTestCase5(keyword)
-
-
diff --git a/tests/teditorstatus.nim b/tests/teditorstatus.nim
index c963e0f3e..6947a9a17 100644
--- a/tests/teditorstatus.nim
+++ b/tests/teditorstatus.nim
@@ -1,7 +1,8 @@
-import unittest
-import moepkg/[ui, highlight, editorview, gapbuffer, unicodeext, insertmode,
- movement, editor, window, color, bufferstatus,
- settings]
+import std/unittest
+import moepkg/[ui, highlight, editorview, gapbuffer, unicodeext,
+ editor, window, color, bufferstatus, settings]
+
+from moepkg/movement import keyDown, keyRight
include moepkg/editorstatus
@@ -11,12 +12,26 @@ template initHighlight() =
status.settings.highlightSettings.reservedWords,
currentBufStatus.language)
-test "Add new buffer":
- var status = initEditorStatus()
- status.addNewBuffer
- status.addNewBuffer
- status.resize(100, 100)
- check(status.bufStatus.len == 2)
+suite "Add new buffer":
+ test "Add 2 uffers":
+ var status = initEditorStatus()
+
+ status.addNewBuffer
+
+ status.resize(100, 100)
+ status.update
+
+ status.addNewBuffer
+
+ check status.bufStatus.len == 2
+
+ test "Add new buffer (Dir)":
+ var status = initEditorStatus()
+
+ status.addNewBuffer("./")
+
+ status.resize(100, 100)
+ status.update
test "Add new buffer and update editor view when disabling current line highlighting (Fix #1189)":
var status = initEditorStatus()
@@ -209,8 +224,9 @@ test "Auto delete paren 1":
status.addNewBuffer
currentBufStatus.buffer = initGapBuffer(@[ru"()"])
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"")
@@ -223,8 +239,9 @@ test "Auto delete paren 1":
currentBufStatus.buffer = initGapBuffer(@[ru"()"])
currentBufStatus.keyRight(currentMainWindowNode)
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"")
@@ -237,8 +254,9 @@ test "Auto delete paren 2":
status.addNewBuffer
currentBufStatus.buffer = initGapBuffer(@[ru"(())"])
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"()")
@@ -251,8 +269,9 @@ test "Auto delete paren 2":
currentBufStatus.buffer = initGapBuffer(@[ru"(())"])
currentBufStatus.keyRight(currentMainWindowNode)
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"()")
@@ -267,8 +286,9 @@ test "Auto delete paren 2":
for i in 0 ..< 2:
currentBufStatus.keyRight(currentMainWindowNode)
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"()")
@@ -282,8 +302,9 @@ test "Auto delete paren 2":
for i in 0 ..< 3:
currentBufStatus.keyRight(currentMainWindowNode)
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"()")
@@ -297,8 +318,9 @@ test "Auto delete paren 3":
currentBufStatus.buffer = initGapBuffer(@[ru"(()"])
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"()")
@@ -311,8 +333,9 @@ test "Auto delete paren 3":
currentBufStatus.buffer = initGapBuffer(@[ru"(()"])
currentBufStatus.keyRight(currentMainWindowNode)
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"(")
@@ -326,8 +349,9 @@ test "Auto delete paren 3":
for i in 0 ..< 2:
currentBufStatus.keyRight(currentMainWindowNode)
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"(")
@@ -339,8 +363,9 @@ test "Auto delete paren 3":
status.addNewBuffer
currentBufStatus.buffer = initGapBuffer(@[ru"())"])
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru")")
@@ -353,8 +378,9 @@ test "Auto delete paren 3":
currentBufStatus.buffer = initGapBuffer(@[ru"())"])
currentBufStatus.keyRight(currentMainWindowNode)
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru")")
@@ -369,8 +395,9 @@ test "Auto delete paren 3":
for i in 0 ..< 3:
currentBufStatus.keyRight(currentMainWindowNode)
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"()")
@@ -383,8 +410,9 @@ test "Auto delete paren 4":
status.addNewBuffer
currentBufStatus.buffer = initGapBuffer(@[ru"(", ru")"])
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"")
@@ -398,8 +426,9 @@ test "Auto delete paren 4":
currentBufStatus.buffer = initGapBuffer(@[ru"(", ru")"])
currentBufStatus.keyDown(currentMainWindowNode)
- currentBufStatus.deleteCurrentCharacter(
- currentMainWindowNode,
+ currentBufStatus.deleteCharacter(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn,
status.settings.autoDeleteParen)
check(currentBufStatus.buffer[0] == ru"")
diff --git a/tests/teditorview.nim b/tests/teditorview.nim
index 724b8c3be..1790e72aa 100644
--- a/tests/teditorview.nim
+++ b/tests/teditorview.nim
@@ -1,4 +1,4 @@
-import unittest, deques
+import std/[unittest, deques]
import moepkg/[editorview, gapbuffer, unicodeext]
test "initEditorView 1":
diff --git a/tests/texmode.nim b/tests/texmode.nim
index 2f4f1d25a..97332eea2 100644
--- a/tests/texmode.nim
+++ b/tests/texmode.nim
@@ -1,4 +1,4 @@
-import unittest, os
+import std/[unittest, os]
import moepkg/[ui, editorstatus, gapbuffer, exmode, unicodeext, bufferstatus,
settings]
diff --git a/tests/tfilermode.nim b/tests/tfilermode.nim
index 884832cda..4a9f840fa 100644
--- a/tests/tfilermode.nim
+++ b/tests/tfilermode.nim
@@ -1,4 +1,4 @@
-import unittest, os, algorithm, strutils
+import std/[unittest, os, algorithm, strutils]
import moepkg/[filermode, editorstatus, highlight, color, bufferstatus,
unicodeext, gapbuffer]
diff --git a/tests/tgapbuffer.nim b/tests/tgapbuffer.nim
index 0377a6cf6..dc634b3b7 100644
--- a/tests/tgapbuffer.nim
+++ b/tests/tgapbuffer.nim
@@ -1,4 +1,4 @@
-import unittest
+import std/unittest
import moepkg/gapbuffer
test "empty":
diff --git a/tests/tgeneralautocomplete.nim b/tests/tgeneralautocomplete.nim
index fa0e41f77..8c651133c 100644
--- a/tests/tgeneralautocomplete.nim
+++ b/tests/tgeneralautocomplete.nim
@@ -1,4 +1,4 @@
-import unittest, sugar, sequtils
+import std/[unittest, sugar, sequtils]
import moepkg/unicodeext
include moepkg/generalautocomplete
diff --git a/tests/thelp.nim b/tests/thelp.nim
index 603e55813..d5e0412bf 100644
--- a/tests/thelp.nim
+++ b/tests/thelp.nim
@@ -1,4 +1,4 @@
-import unittest, strutils
+import std/[unittest, strutils]
import moepkg/[editorstatus, gapbuffer, unicodeext, movement, window,
bufferstatus]
diff --git a/tests/thighlight.nim b/tests/thighlight.nim
index b052d7866..7b0251b58 100644
--- a/tests/thighlight.nim
+++ b/tests/thighlight.nim
@@ -1,4 +1,4 @@
-import unittest, strutils
+import std/[unittest, strutils]
import moepkg/[highlight, color]
import moepkg/syntax/highlite
diff --git a/tests/thighlight_private.nim b/tests/thighlight_private.nim
index e74b643f8..a27154df6 100644
--- a/tests/thighlight_private.nim
+++ b/tests/thighlight_private.nim
@@ -1,4 +1,4 @@
-import unittest, sequtils
+import std/[unittest, sequtils]
include moepkg/highlight
diff --git a/tests/thistorymanager.nim b/tests/thistorymanager.nim
index ce42169eb..1b19aefde 100644
--- a/tests/thistorymanager.nim
+++ b/tests/thistorymanager.nim
@@ -1,4 +1,4 @@
-import unittest, os
+import std/[unittest, os]
import moepkg/[unicodeext, settings]
include moepkg/[historymanager]
diff --git a/tests/tinsertmode.nim b/tests/tinsertmode.nim
index 423fcb602..cf512e3fb 100644
--- a/tests/tinsertmode.nim
+++ b/tests/tinsertmode.nim
@@ -1,4 +1,4 @@
-import unittest, options, sequtils, sugar, random
+import std/[unittest, options, sequtils, sugar, random]
import moepkg/[editorstatus, gapbuffer, unicodeext, highlight, settings]
include moepkg/[insertmode, suggestionwindow]
diff --git a/tests/tlogviewer.nim b/tests/tlogviewer.nim
index 573c19377..92d844115 100644
--- a/tests/tlogviewer.nim
+++ b/tests/tlogviewer.nim
@@ -1,13 +1,41 @@
-import unittest
-import moepkg/[editorstatus, logviewer, bufferstatus]
+import std/unittest
+import moepkg/[editorstatus, logviewer, bufferstatus, unicodeext]
-test "Exit log viewer":
- var status = initEditorStatus()
- status.addNewBuffer("Log viewer", Mode.logViewer)
+suite "Log viewer":
+ test "Open the log viewer (Fix #1455)":
+ var status = initEditorStatus()
+ status.addNewBuffer
- status.resize(100, 100)
- status.update
+ status.resize(100, 100)
+ status.update
- status.exitLogViewer(100, 100)
+ status.messageLog = @[ru "test"]
- status.resize(100, 100)
+ status.verticalSplitWindow
+ status.resize(100, 100)
+ status.moveNextWindow
+
+ status.addNewBuffer
+ status.changeCurrentBuffer(status.bufStatus.high)
+ status.changeMode(bufferstatus.Mode.logviewer)
+
+ # In the log viewer
+ currentBufStatus.path = ru"Log viewer"
+
+ status.resize(100, 100)
+ status.update
+
+ let currentBufferIndex = status.bufferIndexInCurrentWindow
+
+ status.update
+
+ test "Exit viewer":
+ var status = initEditorStatus()
+ status.addNewBuffer("Log viewer", Mode.logViewer)
+
+ status.resize(100, 100)
+ status.update
+
+ status.exitLogViewer(100, 100)
+
+ status.resize(100, 100)
diff --git a/tests/tmovement.nim b/tests/tmovement.nim
index 9df41b61b..ee8786473 100644
--- a/tests/tmovement.nim
+++ b/tests/tmovement.nim
@@ -1,4 +1,4 @@
-import unittest
+import std/unittest
import moepkg/[editorstatus, gapbuffer, unicodeext, highlight, movement,
bufferstatus]
diff --git a/tests/tnormalmode.nim b/tests/tnormalmode.nim
index 8f2773086..d58222933 100644
--- a/tests/tnormalmode.nim
+++ b/tests/tnormalmode.nim
@@ -1,7 +1,7 @@
-import unittest
+import std/unittest
import ncurses
import moepkg/[editorstatus, gapbuffer, unicodeext, editor, bufferstatus,
- register]
+ register, settings]
include moepkg/normalmode
@@ -1591,3 +1591,364 @@ suite "Normal mode: Open the blank line above and enter insert mode":
check currentBufStatus.buffer[1] == ru "abc"
check currentMainWindowNode.currentLine == 0
+
+suite "Normal mode: Run command when Readonly mode":
+ test "Enter insert mode (\"i\") command":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru "abc"])
+
+ const command = ru "i"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.mode == Mode.normal
+
+ test "Enter insert mode (\"I\") command":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru "abc"])
+
+ const command = ru "I"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.mode == Mode.normal
+
+ test "Open the blank line and enter insert mode (\"o\") command":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru "abc"])
+
+ const command = ru "o"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.mode == Mode.normal
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Open the blank line and enter insert mode (\"O\") command":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru "abc"])
+
+ const command = ru "O"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.mode == Mode.normal
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Enter replace mode (\"R\") command":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru "abc"])
+
+ const command = ru "R"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.mode == Mode.normal
+
+ test "Delete lines (\"dd\") command":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru "abc"])
+
+ const command = ru "dd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Paste lines (\"p\") command":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru "abc"])
+
+ var settings = initEditorSettings()
+ settings.clipboard.enable = false
+
+ status.registers.addRegister(ru "def", settings)
+
+ const command = ru "p"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+suite "Normal mode: Move to the next any character on the current line":
+ test "Move to the next 'c' (\"fc\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc def ghi"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "fc"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check currentMainWindowNode.currentLine == 0
+ check currentMainWindowNode.currentColumn == 2
+
+ test "Move to the next 'i' (\"fi\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc def ghi"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "fi"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check currentMainWindowNode.currentLine == 0
+ check currentMainWindowNode.currentColumn == buffer.high
+
+ test "Do nothing (\"fz\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc def ghi"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "fz"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check currentMainWindowNode.currentLine == 0
+ check currentMainWindowNode.currentColumn == 0
+
+suite "Normal mode: Move to forward word in the current line":
+ test "Move to the before 'e' (\"Fe\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc def ghi"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ currentMainWindowNode.currentColumn = buffer.high
+
+ const command = ru "Fe"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check currentMainWindowNode.currentLine == 0
+ check currentMainWindowNode.currentColumn == 5
+
+ test "Do nothing (\"Fz\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc def ghi"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ currentMainWindowNode.currentColumn = buffer.high
+
+ const command = ru "Fz"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check currentMainWindowNode.currentLine == 0
+ check currentMainWindowNode.currentColumn == buffer.high
+
+suite "Normal mode: Move to the left of the next any character":
+ test "Move to the character next the next 'e' (\"tf\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc def ghi"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "tf"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check currentMainWindowNode.currentLine == 0
+ check currentMainWindowNode.currentColumn == 5
+
+ test "Do nothing (\"tz\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc def ghi"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "tz"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check currentMainWindowNode.currentLine == 0
+ check currentMainWindowNode.currentColumn == 0
+
+suite "Normal mode: Move to the right of the back character":
+ test "Move to the character before the next 'f' (\"Te\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc def ghi"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ currentMainWindowNode.currentColumn = buffer.high
+
+ const command = ru "Te"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check currentMainWindowNode.currentLine == 0
+ check currentMainWindowNode.currentColumn == 6
+
+ test "Do nothing (\"Tz\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc def ghi"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "Tz"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check currentMainWindowNode.currentLine == 0
+ check currentMainWindowNode.currentColumn == 0
+
+suite "Normal mode: Yank characters to any character":
+ test "Case 1: Yank characters before 'd' (\"ytd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abcd"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "ytd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check not status.registers.noNameRegister.isLine
+ check status.registers.noNameRegister.buffer[0] == ru "abc"
+
+ test "Case 2: Yank characters before 'd' (\"ytd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "ab c d"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "ytd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check not status.registers.noNameRegister.isLine
+ check status.registers.noNameRegister.buffer[0] == ru "ab c "
+
+ test "Case 1: Do nothing (\"ytd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abc"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "ytd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check status.registers.noNameRegister.buffer.len == 0
+
+ test "Case 2: Do nothing (\"ytd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abcd efg"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+ currentMainWindowNode.currentColumn = 3
+
+ const command = ru "ytd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check status.registers.noNameRegister.buffer.len == 0
+
+ test "Case 3: Do nothing (\"ytd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abcd efg"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+ currentMainWindowNode.currentColumn = buffer.high
+
+ const command = ru "ytd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check status.registers.noNameRegister.buffer.len == 0
+
+suite "Normal mode: Delete characters to any characters and Enter insert mode":
+ test "Case 1: Delete characters to 'd' and enter insert mode (\"cfd\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abcd"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "cfd"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru ""
+
+ check not status.registers.noNameRegister.isLine
+ check status.registers.noNameRegister.buffer[0] == ru "abcd"
+
+ check currentBufStatus.mode == Mode.insert
+
+ test "Case 1: Do nothing (\"cfz\" command)":
+ var status = initEditorStatus()
+ status.addNewBuffer
+
+ const buffer = ru "abcd"
+ currentBufStatus.buffer = initGapBuffer(@[buffer])
+
+ const command = ru "cfz"
+ status.normalCommand(command, 100, 100)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == buffer
+
+ check status.registers.noNameRegister.buffer.len == 0
+
+ check currentBufStatus.mode == Mode.normal
diff --git a/tests/tquittest1.nim b/tests/tquittest1.nim
index 4f200e5bc..b1f4caa3d 100644
--- a/tests/tquittest1.nim
+++ b/tests/tquittest1.nim
@@ -1,4 +1,4 @@
-import unittest
+import std/unittest
import moepkg/[editorstatus, unicodeext, exmode]
test "Quit command":
diff --git a/tests/tquittest2.nim b/tests/tquittest2.nim
index 7c2ea2c0f..4ad5671ac 100644
--- a/tests/tquittest2.nim
+++ b/tests/tquittest2.nim
@@ -1,4 +1,4 @@
-import unittest
+import std/unittest
import moepkg/[editorstatus, unicodeext, exmode, ui]
test "Open buffer manager":
diff --git a/tests/tquittest3.nim b/tests/tquittest3.nim
index e7e93e824..022c21973 100644
--- a/tests/tquittest3.nim
+++ b/tests/tquittest3.nim
@@ -1,4 +1,4 @@
-import unittest
+import std/unittest
import moepkg/[editorstatus, unicodeext, exmode]
test "Force quit command":
diff --git a/tests/tquittest4.nim b/tests/tquittest4.nim
index 1092f1536..ce6cc2d57 100644
--- a/tests/tquittest4.nim
+++ b/tests/tquittest4.nim
@@ -1,4 +1,4 @@
-import unittest
+import std/unittest
import moepkg/[editorstatus, unicodeext, exmode]
test "All buffer quit command":
diff --git a/tests/tquittest5.nim b/tests/tquittest5.nim
index d7e800962..3e5681507 100644
--- a/tests/tquittest5.nim
+++ b/tests/tquittest5.nim
@@ -1,4 +1,4 @@
-import unittest
+import std/unittest
import moepkg/[editorstatus, unicodeext, exmode]
test "All buffer force quit command":
diff --git a/tests/tregister.nim b/tests/tregister.nim
index 2c2f6aec5..d89fbea8e 100644
--- a/tests/tregister.nim
+++ b/tests/tregister.nim
@@ -1,4 +1,4 @@
-import unittest, options
+import std/[unittest, options]
import moepkg/[unicodeext, settings]
include moepkg/[register]
diff --git a/tests/treplacemode.nim b/tests/treplacemode.nim
index b48de20a4..7194b04e2 100644
--- a/tests/treplacemode.nim
+++ b/tests/treplacemode.nim
@@ -1,4 +1,4 @@
-import unittest
+import std/unittest
import moepkg/[editorstatus, bufferstatus, unicodeext]
include moepkg/replacemode
diff --git a/tests/tsearch.nim b/tests/tsearch.nim
index 328ace641..87b5f9592 100644
--- a/tests/tsearch.nim
+++ b/tests/tsearch.nim
@@ -1,5 +1,5 @@
-import unittest
-import moepkg/[editorstatus]
+import std/unittest
+import moepkg/editorstatus
include moepkg/search
diff --git a/tests/tsettings.nim b/tests/tsettings.nim
index 9e1d3250e..fc4e26d39 100644
--- a/tests/tsettings.nim
+++ b/tests/tsettings.nim
@@ -1,4 +1,4 @@
-import unittest, options, strutils
+import std/[unittest, options, strutils]
import moepkg/[color, ui, highlight, unicodeext]
include moepkg/settings
@@ -544,7 +544,7 @@ suite "Validate toml config":
let toml = parsetoml.parseString(tomlStr)
let result = toml.validateTomlConfig
- check result == none(string)
+ check result == none(InvalidItem)
test "Validate vscode theme":
const tomlThemeConfig ="""
@@ -554,7 +554,7 @@ suite "Validate toml config":
let toml = parsetoml.parseString(tomlThemeConfig)
let result = toml.validateTomlConfig
- check result == none(string)
+ check result == none(InvalidItem)
test "Except to fail":
const tomlThemeConfig ="""
@@ -572,7 +572,7 @@ suite "Configuration example":
filename = "./example/moerc.toml"
toml = parsetoml.parseFile(filename)
- check toml.validateTomlConfig == none(string)
+ check toml.validateTomlConfig == none(InvalidItem)
suite "Generate toml config":
test "Generate current config":
@@ -583,4 +583,45 @@ suite "Generate toml config":
toml = parsetoml.parseString(str)
result = toml.validateTomlConfig
- check result == none(string)
+ check result == none(InvalidItem)
+
+suite "Error message":
+ test "Single line":
+ const TOML_STR = """
+ [test]
+ test = "test"
+ """
+
+ let
+ toml = parseString(TOML_STR)
+ result = toml.validateTomlConfig
+ errorMessage = result.get.toValidateErrorMessage
+
+ check errorMessage == """(name: test, val: test = "test")"""
+
+ test "Single line 2":
+ const TOML_STR = """
+ [Standard]
+ test = "test"
+ """
+
+ let
+ toml = parseString(TOML_STR)
+ result = toml.validateTomlConfig
+ errorMessage = result.get.toValidateErrorMessage
+
+ check errorMessage == """(name: test, val: test)"""
+
+ test "Multiple lines":
+ const TOML_STR = """
+ [test]
+ test1 = "test1"
+ test2 = "test2"
+ """
+
+ let
+ toml = parseString(TOML_STR)
+ result = toml.validateTomlConfig
+ errorMessage = result.get.toValidateErrorMessage
+
+ check errorMessage == """(name: test, val: test1 = "test1" test2 = "test2")"""
diff --git a/tests/tunicodeext.nim b/tests/tunicodeext.nim
index ae1a7bb8b..5aac82ec5 100644
--- a/tests/tunicodeext.nim
+++ b/tests/tunicodeext.nim
@@ -1,4 +1,4 @@
-import strutils, unittest, encodings, sequtils, sugar
+import std/[strutils, unittest, encodings, sequtils, sugar]
import moepkg/unicodeext
test "width 1":
diff --git a/tests/tvisualmode.nim b/tests/tvisualmode.nim
index e8cb82286..ad5ff323c 100644
--- a/tests/tvisualmode.nim
+++ b/tests/tvisualmode.nim
@@ -1,4 +1,4 @@
-import unittest, osproc
+import std/[unittest, osproc]
import moepkg/[editorstatus, gapbuffer, unicodeext, highlight, movement, bufferstatus,
register]
include moepkg/[visualmode, platform]
@@ -467,7 +467,8 @@ suite "Visual block mode: Delete buffer (Disable clipboard)":
currentBufStatus.deleteBufferBlock(status.registers,
currentMainWindowNode,
area,
- status.settings)
+ status.settings,
+ status.commandLine)
check(currentBufStatus.buffer[0] == ru"bc")
check(currentBufStatus.buffer[1] == ru"ef")
@@ -695,7 +696,8 @@ suite "Visual block mode: Delete buffer":
currentBufStatus.deleteBufferBlock(status.registers,
currentMainWindowNode,
area,
- status.settings)
+ status.settings,
+ status.commandLine)
if CURRENT_PLATFORM == Platforms.linux:
let (output, exitCode) = execCmdEx("xclip -o")
@@ -733,7 +735,8 @@ suite "Visual block mode: Delete buffer":
currentBufStatus.deleteBufferBlock(status.registers,
currentMainWindowNode,
area,
- status.settings)
+ status.settings,
+ status.commandLine)
test "Fix #885":
var status = initEditorStatus()
@@ -765,10 +768,12 @@ suite "Visual block mode: Delete buffer":
let area = currentBufStatus.selectArea
status.settings.clipboard.enable = true
- currentBufStatus.deleteBufferBlock(status.registers,
+ currentBufStatus.deleteBufferBlock(
+ status.registers,
currentMainWindowNode,
area,
- status.settings)
+ status.settings,
+ status.commandLine)
check currentBufStatus.buffer[0] == ru"c"
check currentBufStatus.buffer[1] == ru""
@@ -805,7 +810,7 @@ suite "Visual mode: Join lines":
let area = currentBufStatus.selectArea
status.update
- currentBufStatus.joinLines(currentMainWindowNode, area)
+ currentBufStatus.joinLines(currentMainWindowNode, area, status.commandLine)
check(currentBufStatus.buffer.len == 1)
check(currentBufStatus.buffer[0] == ru"abcdefghi")
@@ -841,7 +846,7 @@ suite "Visual block mode: Join lines":
let area = currentBufStatus.selectArea
status.update
- currentBufStatus.joinLines(currentMainWindowNode, area)
+ currentBufStatus.joinLines(currentMainWindowNode, area, status.commandLine)
check(currentBufStatus.buffer.len == 1)
check(currentBufStatus.buffer[0] == ru"abcdefghi")
@@ -1401,7 +1406,434 @@ suite "Visual block mode: Insert buffer":
insertBuffer,
area,
status.settings.tabStop,
- status.settings.autoCloseParen)
+ status.settings.autoCloseParen,
+ status.commandLine)
check currentBufStatus.buffer[0] == ru" abc"
check currentBufStatus.buffer[1] == ru" def"
+
+suite "Visual mode: Run command when Readonly mode":
+ test "Delete buffer (\"x\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visual)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'x')
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Add the indent (\">\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visual)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'>')
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Add the indent (\"<\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visual)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'<')
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Join lines (\"J\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc", ru "def"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visual)
+
+ currentMainWindowNode.currentColumn = currentBufStatus.buffer[0].high
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ currentBufStatus.selectArea.endLine = 1
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'J')
+
+ check currentBufStatus.buffer.len == 2
+ check currentBufStatus.buffer[0] == ru "abc"
+ check currentBufStatus.buffer[1] == ru "def"
+
+ test "To lower case (\"u\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visual)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'u')
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "To upper case (\"U\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visual)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'U')
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Replace characters (\"r\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visual)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ currentBufStatus.replaceCharacter(currentBufStatus.selectArea, ru 'z', status.commandLine)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Enter insert mode (\"I\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visual)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'I')
+
+ check currentBufStatus.mode == Mode.visual
+
+suite "Visual block mode: Run command when Readonly mode":
+ test "Delete buffer (\"x\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visualblock)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'x')
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Enter insert mode (\"I\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visualblock)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'I')
+
+ check currentBufStatus.mode == Mode.visualblock
+
+ test "Add the indent (\">\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visualBlock)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'>')
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Add the indent (\"<\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visualBlock)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'<')
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Join lines (\"J\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc", ru "def"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visualBlock)
+
+ currentMainWindowNode.currentColumn = currentBufStatus.buffer[0].high
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ currentBufStatus.selectArea.endLine = 1
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'J')
+
+ check currentBufStatus.buffer.len == 2
+ check currentBufStatus.buffer[0] == ru "abc"
+ check currentBufStatus.buffer[1] == ru "def"
+
+ test "To lower case (\"u\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visualBlock)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'u')
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "To upper case (\"U\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visualBlock)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ status.visualCommand(currentBufStatus.selectArea, ru'U')
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"
+
+ test "Replace characters (\"r\" command)":
+ var status = initEditorStatus()
+ status.isReadonly = true
+ status.addNewBuffer
+ currentBufStatus.buffer = initGapBuffer(@[ru"abc"])
+
+ currentMainWindowNode.highlight = initHighlight(
+ $currentBufStatus.buffer,
+ status.settings.highlightSettings.reservedWords,
+ currentBufStatus.language)
+
+ status.resize(100, 100)
+
+ status.changeMode(Mode.visualBlock)
+
+ currentBufStatus.selectArea = initSelectArea(
+ currentMainWindowNode.currentLine,
+ currentMainWindowNode.currentColumn)
+
+ status.update
+
+ currentBufStatus.replaceCharacter(currentBufStatus.selectArea, ru 'z', status.commandLine)
+
+ check currentBufStatus.buffer.len == 1
+ check currentBufStatus.buffer[0] == ru "abc"