rpgsheet

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit e709acd1400de6119cbd06c3817048d482e8cf50
parent ee0953777e6551dfe419a20fb3a118d72024a361
Author: Skylar Hill <stellarskylark@posteo.net>
Date:   Sun,  5 Jun 2022 21:08:46 -0500

Add new item and item rename functions

Diffstat:
MREADME.md | 2--
Mrpgsheet.nimble | 2+-
Msrc/rpgsheet.nim | 7+++++--
Msrc/tui.nim | 65++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/verb.nim | 32+++++++++++++++++++++++++++++---
5 files changed, 79 insertions(+), 29 deletions(-)

diff --git a/README.md b/README.md @@ -13,8 +13,6 @@ * **Auto-calculation:** You can define values in your character sheet which are dependent on other values. For instance, you can define a hard-coded `proficiency` value, and then define your shortsword attack modifier as `3+proficiency`. (For DnD, you probably actually want a hard-coded `strength` ability score, then a `STR` value defined as `(strength-10)/2`, then define your shortsword attack as `STR+proficiency`.) ## Unimplemented planned features -* Rename character sheet items from within `rpgsheet`. -* Create new items from within `rpgsheet`. * Configurable controls * Be able to have a tab with multiple rows of windows diff --git a/rpgsheet.nimble b/rpgsheet.nimble @@ -1,6 +1,6 @@ # Package -version = "0.2.6" +version = "0.2.7" author = "Skylar Hill" description = "CLI/TUI application for TTRPG character sheets" license = "GPL-3.0-only" diff --git a/src/rpgsheet.nim b/src/rpgsheet.nim @@ -13,7 +13,9 @@ Usage: Options: -v --view View action - -i --interactive Interactive mode (inferred if no action is supplied)""" + -i --interactive Interactive mode (inferred if no action is supplied) + -e --edit Edit the specified action + -n --new Create a new action with the specified name""" proc loadSheet(file: string): YamlDocument = let stream = openFileStream(file, fmRead) @@ -44,6 +46,7 @@ proc main(): void = of "v", "view": verb = View of "i", "interactive": verb = Tui of "e", "edit": verb = Edit + of "n", "new": verb = New else: quit(usage) @@ -57,7 +60,7 @@ proc main(): void = runTui(sheet, sheetLocation) return echo doVerb(action, verb, sheet) - if verb == Edit: + if verb in [Edit, New]: write(sheet, sheetLocation) main() diff --git a/src/tui.nim b/src/tui.nim @@ -209,27 +209,6 @@ proc exitProc(message = "") {.noconv.} = quit(message, 0) -proc command(state: State, file: string): string = - let cmdline = state.commandText - if cmdline == "": - return "" - let tokens = cmdline.split(" ") - var cmd = tokens[0] - case cmd - of "r", "roll": - let action = tokens[1..tokens.high].join(" ").deFancy - result = action.fancyDisplay(-1) & ": " & action.doVerb(Roll, state.sheet) - of "w", "write": - if tokens.len == 2: - state.sheet.write(tokens[1]) - else: - state.sheet.write(file) - of "q", "quit": - exitProc() - else: - result = "command not recognized" - - proc initializeState(state: State): void = let tabs = state.sheet.root["tabs"] for tab in tabs: @@ -271,6 +250,42 @@ proc addToItem(state: State, amt: int): void = state.statusText = sel & " is not an integer value." +proc reloadSheet(state: State) = + state.itemsByWindow = initTable[string, seq[string]]() + initializeState(state) + + +proc command(state: State, file: string): string = + let cmdline = state.commandText + if cmdline == "": + return "" + let tokens = cmdline.split(" ") + var cmd = tokens[0] + case cmd + of "r", "roll": + let action = tokens[1..tokens.high].join(" ").deFancy + result = action.fancyDisplay(-1) & ": " & action.doVerb(Roll, state.sheet) + of "w", "write": + if tokens.len == 2: + state.sheet.write(tokens[1]) + else: + state.sheet.write(file) + of "q", "quit": + exitProc() + of "n", "new": + let action = tokens[1..tokens.high].join(" ").deFancy + result = doVerb(action, New, state.sheet) + hideCursor() + reloadSheet(state) + of "re", "rename": + let newName = tokens[2..tokens.high].join(" ").deFancy + result = state.sheet.rename(tokens[1], newName) + hideCursor() + reloadSheet(state) + else: + result = "command not recognized" + + # Returns 1 if the render loop should immediately restart, # 0 if it should continue normally. proc handleInput(state: State, file: string): int = @@ -372,6 +387,14 @@ proc handleInput(state: State, file: string): int = of Key.E: state.statusText = doVerb(state.selectedItem, Edit, state.sheet) hideCursor() + of Key.N: + state.mode = Command + state.statusText = ":" + state.commandText = "new " + of Key.R: + state.mode = Command + state.statusText = ":" + state.commandText = "rename " & state.selectedItem else: discard diff --git a/src/verb.nim b/src/verb.nim @@ -5,11 +5,13 @@ import std/streams, std/strformat, std/strutils, + std/tables, yaml import utils let reRawExp = re"[\w_~']+" +let reRawValidate = re"^[\w_~']+$" let reProcessedExp = re"^[\d*+\-/()]*$" let reDice = re"(\d+x)?(\d*d[\d%]+)(\*\d+)?([+-]\d+)?(s\d+)?" @@ -19,6 +21,7 @@ type View Tui Edit + New proc expressionAsString(node: YamlNode): string = @@ -98,9 +101,14 @@ proc view(action: string, sheet: YamlDocument): string = echo expressionAsString(node) -proc edit*(action: string, sheet: YamlDocument): string = +proc edit*(action: string, sheet: YamlDocument, isNew = false): string = + if isNew and not action.contains(reRawValidate): + return action & " is not a valid identifier" let outStream = newFileStream("/tmp/rpgsheet-tmp", fmWrite) - initYamlDoc(sheet.expression(action)).dumpDom(outStream) + if isNew: + outStream.write("dice:\nmodifier:\nwindow:\ndesc:") + else: + initYamlDoc(sheet.expression(action)).dumpDom(outStream) outStream.close() if existsEnv("EDITOR"): @@ -120,7 +128,11 @@ proc edit*(action: string, sheet: YamlDocument): string = return "Could not find an editor to use" let inStream = newFileStream("/tmp/rpgsheet-tmp", fmRead) - let key = sheet.root["expressions"].key(action) + var key: YamlNode + if isNew: + key = newYamlNode(action) + else: + key = sheet.root["expressions"].key(action) try: let newNode = inStream.loadDom.root sheet.root["expressions"][key] = newNode @@ -130,6 +142,18 @@ proc edit*(action: string, sheet: YamlDocument): string = finally: inStream.close() +proc rename*(sheet: YamlDocument, action: string, newName: string): string = + let exps = sheet.root["expressions"] + if not exps.contains(action): + return action & " is not a defined expression" + if not newName.contains(reRawValidate): + return newName & " is not a valid identifier" + + let oldKey = exps.key(action) + let newKey = newYamlNode(newName) + exps[newKey] = exps[oldKey] + exps.fields.del(oldKey) + result = fmt"Renamed {action} to {newName}. Remember to update items that reference it!" proc write*(doc: YamlDocument, file: string) = let s = newfileStream(file, fmWrite) @@ -147,3 +171,5 @@ proc doVerb*(action: string, verb: Verb, sheet: YamlDocument): string = raise newException(Exception, "Please report this error, this code should never get run.") of Edit: return edit(action, sheet) + of New: + return edit(action, sheet, true)