create and select entries

This commit is contained in:
2021-06-26 21:42:04 -06:00
parent 8d98ca136c
commit e4e152d26c
9 changed files with 76 additions and 29 deletions

View File

@@ -14,7 +14,8 @@
// Assign entries to the Systems that care about them // Assign entries to the Systems that care about them
(doFor =>id entry entries (doFor =>id entry entries
(system.checkEntryInOrOut this entry)) (system.checkEntryInOrOut this entry))
(systems.push system)) (systems.push system)
system)
(defmethod :Entry createEntry [:Entry->Dynamic initializer] // initializer returns Dynamic so ->:Void isn't required (defmethod :Entry createEntry [:Entry->Dynamic initializer] // initializer returns Dynamic so ->:Void isn't required
(let [e (_newEntry)] (let [e (_newEntry)]
@@ -34,7 +35,17 @@
(Path.join [archiveDir "entries" (e.id.withExtension "json")]) (Path.join [archiveDir "entries" (e.id.withExtension "json")])
(Json.stringify e))) (Json.stringify e)))
// TODO adding or removing components or files should save the Entry and re-check it in or out of systems (defmethod fullData [:Entry e]
(object
id e.id
components
(for =>type id e.components
=>type (haxe.Json.parse (File.getContent (haxe.io.Path.join [archiveDir "components" "$(dictGet e.components type).json"]))))
files
e.files))
(defmethod fullString [:Entry e]
(haxe.Json.stringify (fullData e) null "\t"))
(defun :Entry _newEntry [] (defun :Entry _newEntry []
(object (object

View File

@@ -4,6 +4,7 @@ import kiss.Prelude;
import kiss.List; import kiss.List;
import kiss.Operand; import kiss.Operand;
import haxe.Constraints; import haxe.Constraints;
import uuid.Uuid;
enum CommandArgType { enum CommandArgType {
SelectedEntry; SelectedEntry;

View File

@@ -1,3 +1,5 @@
(load "Lib.kiss")
(defmethod :Void _collectAndValidateArg [:CommandArg arg :Dynamic->Void continuation] (defmethod :Void _collectAndValidateArg [:CommandArg arg :Dynamic->Void continuation]
(case arg.type (case arg.type
(SelectedEntry (SelectedEntry
@@ -67,7 +69,9 @@
(< max entries.length)) (< max entries.length))
(ui.reportError "The requested command expects between $min and $max entries. You chose: $entries.length") (ui.reportError "The requested command expects between $min and $max entries. You chose: $entries.length")
(continuation selectedEntries))))))) (continuation selectedEntries)))
min
max))))
(defmethod :Void->Void _composeArgCollector [:Array<Dynamic> collectedArgs :CommandArg arg :Void->Void lastCollector] (defmethod :Void->Void _composeArgCollector [:Array<Dynamic> collectedArgs :CommandArg arg :Void->Void lastCollector]
(lambda :Void [] (lambda :Void []
@@ -90,18 +94,17 @@
(groups (expList args) 2) (groups (expList args) 2)
methodArgs methodArgs
(for [name type] argPairs (for [name type] argPairs
// TODO write a macroCase macro that simplifies this terrible mess, // TODO write an exprCase macro that simplifies this terrible mess,
// and maybe adds back precise pattern matching instead of relying // and maybe adds back precise pattern matching instead of relying
// on partial string matching // on partial string matching
(let [expAsStr (Std.string type)] (exprCase type
(cond ((exprOr SelectedEntry OneEntry) `:nat.Entry ,name)
((< -1 (max (expAsStr.indexOf "SelectedEntry") (expAsStr.indexOf "OneEntry"))) `:nat.Entry ,name) ((exprOr (SelectedEntries _ _) (Entries _ _)) `:Array<nat.Entry> ,name)
((< -1 (max (expAsStr.indexOf "SelectedEntries") (expAsStr.indexof "Entries"))) `:Array<nat.Entry> ,name) ((Text _ _) `:String ,name)
((< -1 (expAsStr.indexOf "Text")) `:String ,name) ((Number _ _ _) `:Float ,name)))
((< -1 (expAsStr.indexOf "Number")) `:Float ,name))))
commandArgs commandArgs
(for [name type] argPairs (for [name type] argPairs
~`(object name ,(symbolName name) type ,type))] `(object name ,(symbolName name) type ,type))]
`{ `{
(defmethod ,name [,@methodArgs] ,@body) (defmethod ,name [,@methodArgs] ,@body)
(dictSet commands ,(symbolName name) (object args [,@commandArgs] handler (the Function ,name)))})) (dictSet commands ,(symbolName name) (object args [,@commandArgs] handler (the Function ,name)))}))
@@ -115,13 +118,15 @@
(defcommand selectEntry [e OneEntry] (defcommand selectEntry [e OneEntry]
(set selectedEntries [e])) (set selectedEntries [e]))
/*
(defcommand selectEntries [entries (Entries null null)] (defcommand selectEntries [entries (Entries null null)]
(set selectedEntries entries)) (set selectedEntries entries))
*/
(defcommand selectLastChangeSet [] (defcommand selectLastChangeSet []
(set selectedEntries lastChangeSet)) (set selectedEntries lastChangeSet))
(defcommand printSelectedEntries [entries (SelectedEntries null null)]
(doFor e entries (ui.displayMessage (archive.fullString e))))
/*(defcommand createEntry [name (Text null null)] (defcommand createEntry [name (Text null null)]
~name)*/) (archive.createEntry ->e
(addComponent archive e Name name))))

View File

@@ -6,12 +6,12 @@ interface ArchiveUI {
/** /**
* Prompt the user to enter text * Prompt the user to enter text
*/ */
function enterText(prompt:String, resolve:(String) -> Void, ?minLength:Int, ?maxLength:Float):Void; function enterText(prompt:String, resolve:(String) -> Void, minLength:Int, maxLength:Float):Void;
/** /**
* Prompt the user to enter a number * Prompt the user to enter a number
*/ */
function enterNumber(prompt:String, resolve:(Float) -> Void, ?min:Float, ?max:Float, ?inStepsOf:Float):Void; function enterNumber(prompt:String, resolve:(Float) -> Void, min:Float, max:Float, ?inStepsOf:Float):Void;
/** /**
* Prompt the user to choose a single Entry * Prompt the user to choose a single Entry
@@ -21,13 +21,18 @@ interface ArchiveUI {
/** /**
* Prompt the user to choose multiple Entries * Prompt the user to choose multiple Entries
*/ */
function chooseEntries(prompt:String, archive:Archive, resolve:(Array<Entry>) -> Void, ?min:Int, ?max:Float):Void; function chooseEntries(prompt:String, archive:Archive, resolve:(Array<Entry>) -> Void, min:Int, max:Float):Void;
/** /**
* Update the interface to reflect changes made to Entries through commands * Update the interface to reflect changes made to Entries through commands
*/ */
function handleChanges(changeSet:ChangeSet):Void; function handleChanges(changeSet:ChangeSet):Void;
/**
* Tell the user something useful
*/
function displayMessage(message:String):Void;
/** /**
* Tell the user that something is wrong * Tell the user that something is wrong
*/ */

View File

@@ -5,6 +5,7 @@ import kiss.List;
import kiss.Operand; import kiss.Operand;
import sys.FileSystem; import sys.FileSystem;
import nat.ArchiveController.CommandArgType; import nat.ArchiveController.CommandArgType;
using StringTools;
@:build(kiss.Kiss.build()) @:build(kiss.Kiss.build())
class CLI implements ArchiveUI {} class CLI implements ArchiveUI {}

View File

@@ -1,14 +1,20 @@
(load "Lib.kiss")
(defun :Void main [] (defun :Void main []
(let [[archiveDir] (Sys.args) (let [[archiveDir] (Sys.args)
controller controller
(new ArchiveController (new ArchiveController
(new Archive archiveDir) (new Archive archiveDir)
(new CLI))] (new CLI))]
(controller.runCommand (dictGet controller.commands "selectEntry")))) (loop
(Sys.print ">> ")
(let [command
(.trim (.toString (.readLine (Sys.stdin))))]
(controller.runCommand (dictGet controller.commands command))))))
(defnew []) (defnew [])
(defmethod :Void enterText [prompt resolve &opt minLength maxLength] (defmethod :Void enterText [prompt resolve minLength maxLength]
(Sys.print "$prompt ") (Sys.print "$prompt ")
(loop (loop
(let [entered (.toString (.readLine (Sys.stdin)))] (let [entered (.toString (.readLine (Sys.stdin)))]
@@ -17,7 +23,7 @@
{(resolve entered) {(resolve entered)
(break)})))) (break)}))))
(defmethod :Void enterNumber [prompt resolve &opt min max inStepsOf] (defmethod :Void enterNumber [prompt resolve min max &opt inStepsOf]
(Sys.print "$prompt ") (Sys.print "$prompt ")
(loop (loop
(let [entered (Std.parseFloat (.toString (.readLine (Sys.stdin))))] (let [entered (Std.parseFloat (.toString (.readLine (Sys.stdin))))]
@@ -29,12 +35,28 @@
{(resolve entered) {(resolve entered)
(break)})))) (break)}))))
(defmethod :Void chooseEntry [prompt archive resolve] (defmethod :Void chooseEntry [prompt :Archive archive resolve]
(resolve null)) // TODO allow narrowing down with a tag string
(enterText "entry name for $prompt"
->name {
(let [matchingEntries []]
(.process (archive.addSystem
(stringComponentSystem archive Name name
(lambda [archive e]
(matchingEntries.push e)))) archive)
(defmethod :Void chooseEntries [prompt archive resolve &opt min max] (case (the Array<Entry> matchingEntries)
([e] (resolve e))
// TODO disambiguate entries with the same names by listing stringified versions of them and using enterNumber
(multipleEntries (throw "ambiguous between multiple entries"))))}
0 Math.POSITIVE_INFINITY))
(defmethod :Void chooseEntries [prompt archive resolve min max]
(resolve [])) (resolve []))
(defmethod handleChanges [changeSet]) (defmethod handleChanges [changeSet])
(defmethod :Void displayMessage [message]
(print message))
(defmethod :Void reportError [error] ~error) (defmethod :Void reportError [error] ~error)

View File

@@ -3,7 +3,7 @@ package nat;
import kiss.Prelude; import kiss.Prelude;
typedef EntryChecker = (Archive, Entry) -> Bool; typedef EntryChecker = (Archive, Entry) -> Bool;
typedef EntryProcessor = (Archive, Entry) -> Void; typedef EntryProcessor = (Archive, Entry) -> Dynamic; // Whatever value is returned will be dropped, but this is easier than requiring ->:Void
@:build(kiss.Kiss.build()) @:build(kiss.Kiss.build())
class System {} class System {}

View File

@@ -1,7 +1,9 @@
(defprop :Map<String,Entry> entries (new Map)) (defprop :Map<String,Entry> entries (new Map))
(defmethod :Void process [:Archive archive] (defmethod :Void process [:Archive archive]
(doFor e (entries.iterator) (processEntry archive e))) (doFor e (entries.iterator)
(processEntry archive e)
(archive.refreshEntry e)))
(defnew [&prop :EntryChecker canProcessEntry (defnew [&prop :EntryChecker canProcessEntry
&prop :EntryProcessor processEntry] &prop :EntryProcessor processEntry]

View File

@@ -1,8 +1,8 @@
(load "../Lib.kiss") (load "../Lib.kiss")
// TODO make a &super annotation that passes an argument to the super constructor (defnew [&prop :String tagFilterString // This doesn't need to be a &prop because it will be captured by the lambda, but maybe it will be useful to query from the system later
(defnew [&prop :String tagFilterString // TODO make a &super annotation that passes an argument to the super constructor
&prop :EntryProcessor processor] :EntryProcessor processor]
[] []
(super (super
(lambda [:Archive archive :Entry e] (tagsMatch archive e tagFilterString)) (lambda [:Archive archive :Entry e] (tagsMatch archive e tagFilterString))