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:
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)