diff --git a/src/moe.nim b/src/moe.nim index 7ff1724a7..b0f681327 100644 --- a/src/moe.nim +++ b/src/moe.nim @@ -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/bufferstatus.nim b/src/moepkg/bufferstatus.nim index 0166fc04c..e9f9474c5 100644 --- a/src/moepkg/bufferstatus.nim +++ b/src/moepkg/bufferstatus.nim @@ -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/cmdlineoption.nim b/src/moepkg/cmdlineoption.nim index a48e97458..1beeb1e98 100644 --- a/src/moepkg/cmdlineoption.nim +++ b/src/moepkg/cmdlineoption.nim @@ -1,6 +1,8 @@ import 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/editorstatus.nim b/src/moepkg/editorstatus.nim index 630f568c2..4078fbe56 100644 --- a/src/moepkg/editorstatus.nim +++ b/src/moepkg/editorstatus.nim @@ -31,6 +31,7 @@ type EditorStatus* = object autoBackupStatus*: AutoBackupStatus isSearchHighlight*: bool lastPosition*: seq[LastPosition] + isReadonly*: bool proc initEditorStatus*(): EditorStatus = result.currentDir = getCurrentDir().toRunes @@ -723,6 +724,8 @@ proc addNewBuffer*(status: var EditorStatus, filename: string, mode: Mode) = let index = status.bufStatus.high + status.bufStatus[index].isReadonly = status.isReadonly + if mode != Mode.filer: if not fileExists(filename): status.bufStatus[index].buffer = newFile() diff --git a/src/moepkg/messages.nim b/src/moepkg/messages.nim index ea6af8e1c..2ae5664b6 100644 --- a/src/moepkg/messages.nim +++ b/src/moepkg/messages.nim @@ -4,10 +4,12 @@ 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/normalmode.nim b/src/moepkg/normalmode.nim index 2d9aef937..b27c46c78 100644 --- a/src/moepkg/normalmode.nim +++ b/src/moepkg/normalmode.nim @@ -155,6 +155,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 +177,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 +210,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 +241,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 +272,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 +388,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 +406,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( @@ -436,6 +464,10 @@ proc yankCharacters(status: var Editorstatus, registerName: string) = isDelete) proc deleteCharacters(status: var EditorStatus, registerName: string) = + if currentBufStatus.isReadonly: + status.commandLine.writeReadonlyModeWarning + return + currentBufStatus.deleteCharacters( status.registers, registerName, @@ -445,6 +477,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 +494,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 +509,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 +527,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 +539,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 +551,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 +570,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 +589,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 +600,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 +611,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 +623,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,23 +640,43 @@ 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.isReadonly: + status.commandLine.writeReadonlyModeWarning + return + if currentBufStatus.buffer[currentMainWindowNode.currentLine].len > 0: let lineWidth = currentBufStatus.buffer[currentMainWindowNode.currentLine].len @@ -596,6 +692,10 @@ proc deleteCharacterAndEnterInsertMode(status: var EditorStatus) = 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 @@ -609,6 +709,10 @@ proc deleteCharacterAndEnterInsertMode(status: var EditorStatus, # cc/S command proc deleteCharactersAfterBlankInLine(status: var EditorStatus) = + if currentBufStatus.isReadonly: + status.commandLine.writeReadonlyModeWarning + return + const registerName = "" currentBufStatus.deleteCharactersAfterBlankInLine( status.registers, @@ -617,6 +721,10 @@ proc deleteCharactersAfterBlankInLine(status: var EditorStatus) = status.settings) 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 +732,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 +754,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 +782,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 @@ -706,6 +847,10 @@ proc addRegister(status: var EditorStatus, command, registerName: string) = discard proc pasteFromRegister(status: var EditorStatus, command, name: string) = + if currentBufStatus.isReadonly: + status.commandLine.writeReadonlyModeWarning + return + if name.len == 0: return case command: @@ -793,6 +938,30 @@ 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.} = + if currentBufStatus.isReadonly: + status.commandLine.writeReadonlyModeWarning + else: + status.changeMode(Mode.visual) + +proc changeModeToVisualBlockMode(status: var EditorStatus) {.inline.} = + if currentBufStatus.isReadonly: + status.commandLine.writeReadonlyModeWarning + else: + status.changeMode(Mode.visualBlock) + proc normalCommand(status: var EditorStatus, commands: seq[Rune], height, width: int) = @@ -812,7 +981,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): @@ -982,20 +1151,17 @@ proc normalCommand(status: var EditorStatus, currentMainWindowNode, secondKey) 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):