create and select entries
This commit is contained in:
@@ -14,7 +14,8 @@
|
||||
// Assign entries to the Systems that care about them
|
||||
(doFor =>id entry entries
|
||||
(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
|
||||
(let [e (_newEntry)]
|
||||
@@ -34,7 +35,17 @@
|
||||
(Path.join [archiveDir "entries" (e.id.withExtension "json")])
|
||||
(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 []
|
||||
(object
|
||||
|
@@ -4,6 +4,7 @@ import kiss.Prelude;
|
||||
import kiss.List;
|
||||
import kiss.Operand;
|
||||
import haxe.Constraints;
|
||||
import uuid.Uuid;
|
||||
|
||||
enum CommandArgType {
|
||||
SelectedEntry;
|
||||
|
@@ -1,3 +1,5 @@
|
||||
(load "Lib.kiss")
|
||||
|
||||
(defmethod :Void _collectAndValidateArg [:CommandArg arg :Dynamic->Void continuation]
|
||||
(case arg.type
|
||||
(SelectedEntry
|
||||
@@ -67,7 +69,9 @@
|
||||
(< max 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]
|
||||
(lambda :Void []
|
||||
@@ -90,18 +94,17 @@
|
||||
(groups (expList args) 2)
|
||||
methodArgs
|
||||
(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
|
||||
// on partial string matching
|
||||
(let [expAsStr (Std.string type)]
|
||||
(cond
|
||||
((< -1 (max (expAsStr.indexOf "SelectedEntry") (expAsStr.indexOf "OneEntry"))) `:nat.Entry ,name)
|
||||
((< -1 (max (expAsStr.indexOf "SelectedEntries") (expAsStr.indexof "Entries"))) `:Array<nat.Entry> ,name)
|
||||
((< -1 (expAsStr.indexOf "Text")) `:String ,name)
|
||||
((< -1 (expAsStr.indexOf "Number")) `:Float ,name))))
|
||||
(exprCase type
|
||||
((exprOr SelectedEntry OneEntry) `:nat.Entry ,name)
|
||||
((exprOr (SelectedEntries _ _) (Entries _ _)) `:Array<nat.Entry> ,name)
|
||||
((Text _ _) `:String ,name)
|
||||
((Number _ _ _) `:Float ,name)))
|
||||
commandArgs
|
||||
(for [name type] argPairs
|
||||
~`(object name ,(symbolName name) type ,type))]
|
||||
`(object name ,(symbolName name) type ,type))]
|
||||
`{
|
||||
(defmethod ,name [,@methodArgs] ,@body)
|
||||
(dictSet commands ,(symbolName name) (object args [,@commandArgs] handler (the Function ,name)))}))
|
||||
@@ -115,13 +118,15 @@
|
||||
(defcommand selectEntry [e OneEntry]
|
||||
(set selectedEntries [e]))
|
||||
|
||||
/*
|
||||
(defcommand selectEntries [entries (Entries null null)]
|
||||
(set selectedEntries entries))
|
||||
*/
|
||||
|
||||
(defcommand selectLastChangeSet []
|
||||
(set selectedEntries lastChangeSet))
|
||||
|
||||
(defcommand printSelectedEntries [entries (SelectedEntries null null)]
|
||||
(doFor e entries (ui.displayMessage (archive.fullString e))))
|
||||
|
||||
/*(defcommand createEntry [name (Text null null)]
|
||||
~name)*/)
|
||||
(defcommand createEntry [name (Text null null)]
|
||||
(archive.createEntry ->e
|
||||
(addComponent archive e Name name))))
|
@@ -6,12 +6,12 @@ interface ArchiveUI {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
@@ -21,13 +21,18 @@ interface ArchiveUI {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function handleChanges(changeSet:ChangeSet):Void;
|
||||
|
||||
/**
|
||||
* Tell the user something useful
|
||||
*/
|
||||
function displayMessage(message:String):Void;
|
||||
|
||||
/**
|
||||
* Tell the user that something is wrong
|
||||
*/
|
||||
|
@@ -5,6 +5,7 @@ import kiss.List;
|
||||
import kiss.Operand;
|
||||
import sys.FileSystem;
|
||||
import nat.ArchiveController.CommandArgType;
|
||||
using StringTools;
|
||||
|
||||
@:build(kiss.Kiss.build())
|
||||
class CLI implements ArchiveUI {}
|
||||
|
@@ -1,14 +1,20 @@
|
||||
(load "Lib.kiss")
|
||||
|
||||
(defun :Void main []
|
||||
(let [[archiveDir] (Sys.args)
|
||||
controller
|
||||
(new ArchiveController
|
||||
(new Archive archiveDir)
|
||||
(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 [])
|
||||
|
||||
(defmethod :Void enterText [prompt resolve &opt minLength maxLength]
|
||||
(defmethod :Void enterText [prompt resolve minLength maxLength]
|
||||
(Sys.print "$prompt ")
|
||||
(loop
|
||||
(let [entered (.toString (.readLine (Sys.stdin)))]
|
||||
@@ -17,7 +23,7 @@
|
||||
{(resolve entered)
|
||||
(break)}))))
|
||||
|
||||
(defmethod :Void enterNumber [prompt resolve &opt min max inStepsOf]
|
||||
(defmethod :Void enterNumber [prompt resolve min max &opt inStepsOf]
|
||||
(Sys.print "$prompt ")
|
||||
(loop
|
||||
(let [entered (Std.parseFloat (.toString (.readLine (Sys.stdin))))]
|
||||
@@ -29,12 +35,28 @@
|
||||
{(resolve entered)
|
||||
(break)}))))
|
||||
|
||||
(defmethod :Void chooseEntry [prompt archive resolve]
|
||||
(resolve null))
|
||||
(defmethod :Void chooseEntry [prompt :Archive archive resolve]
|
||||
// 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 []))
|
||||
|
||||
(defmethod handleChanges [changeSet])
|
||||
|
||||
(defmethod :Void displayMessage [message]
|
||||
(print message))
|
||||
|
||||
(defmethod :Void reportError [error] ~error)
|
@@ -3,7 +3,7 @@ package nat;
|
||||
import kiss.Prelude;
|
||||
|
||||
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())
|
||||
class System {}
|
||||
|
@@ -1,7 +1,9 @@
|
||||
(defprop :Map<String,Entry> entries (new Map))
|
||||
|
||||
(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
|
||||
&prop :EntryProcessor processEntry]
|
||||
|
@@ -1,8 +1,8 @@
|
||||
(load "../Lib.kiss")
|
||||
|
||||
// TODO make a &super annotation that passes an argument to the super constructor
|
||||
(defnew [&prop :String tagFilterString
|
||||
&prop :EntryProcessor processor]
|
||||
(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
|
||||
// TODO make a &super annotation that passes an argument to the super constructor
|
||||
:EntryProcessor processor]
|
||||
[]
|
||||
(super
|
||||
(lambda [:Archive archive :Entry e] (tagsMatch archive e tagFilterString))
|
||||
|
Reference in New Issue
Block a user