technically works... lesgoo
This commit is contained in:
parent
e134f20fca
commit
17ac128890
6 changed files with 797 additions and 582 deletions
12
flake.nix
12
flake.nix
|
@ -12,10 +12,20 @@
|
||||||
devShells.${system} = {
|
devShells.${system} = {
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
pkgs.elmPackages.elm-format
|
|
||||||
pkgs.elm2nix
|
pkgs.elm2nix
|
||||||
|
pkgs.elmPackages.elm
|
||||||
|
pkgs.elmPackages.elm-format
|
||||||
pkgs.elmPackages.elm-json
|
pkgs.elmPackages.elm-json
|
||||||
|
pkgs.elmPackages.elm-review
|
||||||
|
pkgs.tokei
|
||||||
];
|
];
|
||||||
|
shellHook = ''
|
||||||
|
${pkgs.elmPackages.fetchElmDeps {
|
||||||
|
elmPackages = import ./src/elm2nix/elm-srcs.nix;
|
||||||
|
elmVersion = "0.19.1";
|
||||||
|
registryDat = ./src/elm2nix/registry.dat;
|
||||||
|
}}
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
264
src/Cli.elm
264
src/Cli.elm
|
@ -1,14 +1,53 @@
|
||||||
module Cli exposing (..)
|
module Cli exposing (..)
|
||||||
|
{- ( Command
|
||||||
|
, CommandErr
|
||||||
|
, FilledCommand
|
||||||
|
, FilledFlag
|
||||||
|
, FilledFlagOption
|
||||||
|
, FilledOption
|
||||||
|
, Flag
|
||||||
|
, FlagOption
|
||||||
|
, Option
|
||||||
|
, getFlag
|
||||||
|
, getFlagOption
|
||||||
|
, getOption
|
||||||
|
, mkCommand
|
||||||
|
, parseInput
|
||||||
|
)
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
type alias Parameter =
|
|
||||||
|
type alias Option =
|
||||||
{ name : String
|
{ name : String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type alias FilledParameter =
|
type alias FilledOption =
|
||||||
{ name : String
|
{ name : String
|
||||||
, content : String
|
, value : Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Flag =
|
||||||
|
{ name : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias FilledFlag =
|
||||||
|
{ name : String
|
||||||
|
, value : Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias FlagOption =
|
||||||
|
{ name : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias FilledFlagOption =
|
||||||
|
{ name : String
|
||||||
|
, value : Maybe String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,13 +57,17 @@ type alias DirtyCommand =
|
||||||
|
|
||||||
type alias Command =
|
type alias Command =
|
||||||
{ name : String
|
{ name : String
|
||||||
, params : List Parameter
|
, opts : List Option
|
||||||
|
, flags : List Flag
|
||||||
|
, flagOpts : List FlagOption
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type alias FilledCommand =
|
type alias FilledCommand =
|
||||||
{ name : String
|
{ name : String
|
||||||
, params : List FilledParameter
|
, opts : List FilledOption
|
||||||
|
, flags : List FilledFlag
|
||||||
|
, flagOpts : List FilledFlagOption
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,40 +77,49 @@ type alias CommandErr =
|
||||||
, argumentErr : Maybe ArgumentErr
|
, argumentErr : Maybe ArgumentErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type ArgumentErr
|
type ArgumentErr
|
||||||
= MissingArgs
|
= MissingArgs
|
||||||
| TooManyArgs
|
| TooManyArgs
|
||||||
|
| UnrecognisedFlag
|
||||||
|
|
||||||
|
|
||||||
parseInput : List Command -> String -> Result CommandErr FilledCommand
|
parseInput : List Command -> String -> Result CommandErr FilledCommand
|
||||||
parseInput commands input =
|
parseInput commands input =
|
||||||
let
|
let
|
||||||
tokens =
|
tokens =
|
||||||
List.map String.trim (String.split " " input)
|
String.words input
|
||||||
|
|
||||||
|
tail =
|
||||||
|
case List.tail tokens of
|
||||||
|
Just t ->
|
||||||
|
t
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
[]
|
||||||
in
|
in
|
||||||
case List.head tokens of
|
case List.head tokens of
|
||||||
Just maybeCommand ->
|
Just maybeCommand ->
|
||||||
case List.head (List.filter (isCommand maybeCommand) commands) of
|
case List.head (List.filter (isCommand maybeCommand) commands) of
|
||||||
Just command ->
|
Just command ->
|
||||||
case applyArguments command.params tokens of
|
case applyArguments command tail of
|
||||||
Ok list ->
|
Ok filledCommand ->
|
||||||
Ok
|
Ok filledCommand
|
||||||
{ name = command.name
|
|
||||||
, params = list
|
|
||||||
}
|
|
||||||
Err err ->
|
Err err ->
|
||||||
Err { command = Just command
|
Err
|
||||||
|
{ command = Just command
|
||||||
, got = input
|
, got = input
|
||||||
, argumentErr = Just err
|
, argumentErr = Just err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
Err
|
Err
|
||||||
{ command = Nothing
|
{ command = Nothing
|
||||||
, got = input
|
, got = input
|
||||||
, argumentErr = Nothing
|
, argumentErr = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
Err
|
Err
|
||||||
{ command = Nothing
|
{ command = Nothing
|
||||||
|
@ -76,22 +128,151 @@ parseInput commands input =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
applyArguments : List Parameter -> List String -> Result ArgumentErr (List FilledParameter)
|
mkCommand : Command -> Command
|
||||||
applyArguments params inputs =
|
mkCommand command =
|
||||||
if List.length params > List.length inputs then
|
{ command | flags = List.append command.flags [ { name = "--help" } ] }
|
||||||
Err MissingArgs
|
|
||||||
else if List.length params < List.length inputs then
|
|
||||||
|
flagsFromTokens : List String -> List String
|
||||||
|
flagsFromTokens tokens =
|
||||||
|
tokens
|
||||||
|
|> List.filter isFlag
|
||||||
|
|
||||||
|
|
||||||
|
flagOptionsFromTokens : List String -> List String
|
||||||
|
flagOptionsFromTokens flags =
|
||||||
|
flags
|
||||||
|
|> List.filter isFlagOption
|
||||||
|
|
||||||
|
|
||||||
|
nonFlagsFromTokens : List String -> List String
|
||||||
|
nonFlagsFromTokens tokens =
|
||||||
|
tokens
|
||||||
|
|> List.filter (not << isFlag)
|
||||||
|
|> List.filter (not << isFlagOption)
|
||||||
|
|
||||||
|
|
||||||
|
isFlag : String -> Bool
|
||||||
|
isFlag str =
|
||||||
|
String.startsWith "--" str && not (String.contains "=" str)
|
||||||
|
|
||||||
|
|
||||||
|
isFlagOption : String -> Bool
|
||||||
|
isFlagOption str =
|
||||||
|
String.startsWith "--" str && isOnlyOnce "=" str
|
||||||
|
|
||||||
|
|
||||||
|
isOnlyOnce : String -> String -> Bool
|
||||||
|
isOnlyOnce a b =
|
||||||
|
1 == List.length (String.indices a b)
|
||||||
|
|
||||||
|
|
||||||
|
applyArguments : Command -> List String -> Result ArgumentErr FilledCommand
|
||||||
|
applyArguments command tokens =
|
||||||
|
let
|
||||||
|
opts =
|
||||||
|
command.opts
|
||||||
|
|
||||||
|
flags =
|
||||||
|
command.flags
|
||||||
|
|
||||||
|
flagOpts =
|
||||||
|
command.flagOpts
|
||||||
|
|
||||||
|
flagIns =
|
||||||
|
flagsFromTokens tokens
|
||||||
|
|
||||||
|
flagOptIns =
|
||||||
|
flagOptionsFromTokens tokens
|
||||||
|
|
||||||
|
nonFlagIns =
|
||||||
|
nonFlagsFromTokens tokens
|
||||||
|
in
|
||||||
|
if List.length opts < List.length nonFlagIns then
|
||||||
Err TooManyArgs
|
Err TooManyArgs
|
||||||
else
|
|
||||||
Ok (List.map2 applyParameter params inputs)
|
|
||||||
|
|
||||||
|
else if List.any (\m -> not (List.member { name = m } flags)) flagIns then
|
||||||
|
Err UnrecognisedFlag
|
||||||
|
|
||||||
|
else if
|
||||||
|
List.any
|
||||||
|
(\m ->
|
||||||
|
not
|
||||||
|
(List.member
|
||||||
|
{ name =
|
||||||
|
case List.head (String.split "=" m) of
|
||||||
|
Just head ->
|
||||||
|
head
|
||||||
|
|
||||||
applyParameter : Parameter -> String -> FilledParameter
|
Nothing ->
|
||||||
applyParameter param input =
|
""
|
||||||
{ name = param.name
|
|
||||||
, content = input
|
|
||||||
}
|
}
|
||||||
|
flagOpts
|
||||||
|
)
|
||||||
|
)
|
||||||
|
flagOptIns
|
||||||
|
then
|
||||||
|
Err UnrecognisedFlag
|
||||||
|
|
||||||
|
else
|
||||||
|
let
|
||||||
|
optionInputs =
|
||||||
|
expandList (List.map Just nonFlagIns) (List.length opts)
|
||||||
|
in
|
||||||
|
Ok
|
||||||
|
{ name = command.name
|
||||||
|
, opts = List.map2 applyOption opts optionInputs
|
||||||
|
, flags = List.map (fillFlag flagIns) flags
|
||||||
|
, flagOpts = List.map (fillFlagOption flagOptIns) flagOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applyOption : Option -> Maybe String -> FilledOption
|
||||||
|
applyOption option input =
|
||||||
|
{ name = option.name
|
||||||
|
, value = input
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fillFlag : List String -> Flag -> FilledFlag
|
||||||
|
fillFlag flagTokens flag =
|
||||||
|
if List.member flag.name flagTokens then
|
||||||
|
{ name = flag.name
|
||||||
|
, value = True
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{ name = flag.name
|
||||||
|
, value = False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fillFlagOption : List String -> FlagOption -> FilledFlagOption
|
||||||
|
fillFlagOption flagOptIns flagOption =
|
||||||
|
let
|
||||||
|
flag =
|
||||||
|
case flagOptIns
|
||||||
|
|> List.filter (\m->String.contains flagOption.name m)
|
||||||
|
|> List.head
|
||||||
|
of
|
||||||
|
Just head ->
|
||||||
|
Just <| String.dropLeft (1 + String.length flagOption.name) head
|
||||||
|
Nothing ->
|
||||||
|
Nothing
|
||||||
|
|
||||||
|
in
|
||||||
|
{ name = flagOption.name
|
||||||
|
, value = flag
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
expandList : List (Maybe String) -> Int -> List (Maybe String)
|
||||||
|
expandList input len =
|
||||||
|
if List.length input >= len then
|
||||||
|
List.take len input
|
||||||
|
|
||||||
|
else
|
||||||
|
expandList (List.append input [ Nothing ]) len
|
||||||
|
|
||||||
|
|
||||||
isCommand : String -> Command -> Bool
|
isCommand : String -> Command -> Bool
|
||||||
|
@ -101,3 +282,36 @@ isCommand name command =
|
||||||
|
|
||||||
else
|
else
|
||||||
False
|
False
|
||||||
|
|
||||||
|
|
||||||
|
getOption : FilledCommand -> String -> FilledOption
|
||||||
|
getOption command name =
|
||||||
|
case List.head <| List.filter (\m->m.name == name) command.opts of
|
||||||
|
Just head ->
|
||||||
|
head
|
||||||
|
Nothing ->
|
||||||
|
{ name = name
|
||||||
|
, value = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getFlag : FilledCommand -> String -> FilledFlag
|
||||||
|
getFlag command name =
|
||||||
|
case List.head <| List.filter (\m->m.name == name) command.flags of
|
||||||
|
Just head ->
|
||||||
|
head
|
||||||
|
Nothing ->
|
||||||
|
{ name = name
|
||||||
|
, value = False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getFlagOption : FilledCommand -> String -> FilledFlagOption
|
||||||
|
getFlagOption command name =
|
||||||
|
case List.head <| List.filter (\m->m.name == name) command.flagOpts of
|
||||||
|
Just head ->
|
||||||
|
head
|
||||||
|
Nothing ->
|
||||||
|
{ name = name
|
||||||
|
, value = Nothing
|
||||||
|
}
|
||||||
|
|
113
src/Commands.elm
113
src/Commands.elm
|
@ -1,12 +1,111 @@
|
||||||
module Commands exposing (..)
|
module Commands exposing (..)
|
||||||
|
|
||||||
import Cli exposing (Command)
|
import Cli exposing (Command, mkCommand)
|
||||||
|
|
||||||
|
|
||||||
greet : Command
|
commands : List Command
|
||||||
greet =
|
commands =
|
||||||
{ name = "greet"
|
[ help
|
||||||
, params = [
|
, clear
|
||||||
{ name = "name"
|
, colors
|
||||||
} ]
|
, cookies
|
||||||
|
, debug
|
||||||
|
, environment
|
||||||
|
, hello
|
||||||
|
, todo
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
help : Command
|
||||||
|
help =
|
||||||
|
{ name = "help"
|
||||||
|
, opts =
|
||||||
|
[ { name = "command" }
|
||||||
|
]
|
||||||
|
, flags = []
|
||||||
|
, flagOpts = []
|
||||||
}
|
}
|
||||||
|
|> mkCommand
|
||||||
|
|
||||||
|
|
||||||
|
clear : Command
|
||||||
|
clear =
|
||||||
|
{ name = "clear"
|
||||||
|
, opts = []
|
||||||
|
, flags = []
|
||||||
|
, flagOpts = []
|
||||||
|
}
|
||||||
|
|> mkCommand
|
||||||
|
|
||||||
|
|
||||||
|
colors : Command
|
||||||
|
colors =
|
||||||
|
{ name = "colors"
|
||||||
|
, opts =
|
||||||
|
[ { name = "show" }
|
||||||
|
]
|
||||||
|
, flags = []
|
||||||
|
, flagOpts = []
|
||||||
|
}
|
||||||
|
|> mkCommand
|
||||||
|
|
||||||
|
|
||||||
|
cookies : Command
|
||||||
|
cookies =
|
||||||
|
{ name = "cookies"
|
||||||
|
, opts =
|
||||||
|
[ { name = "show" }
|
||||||
|
]
|
||||||
|
, flags = []
|
||||||
|
, flagOpts =
|
||||||
|
[ { name = "--keepFont" }
|
||||||
|
, { name = "--keepPrompt" }
|
||||||
|
, { name = "--keepTheme" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|> mkCommand
|
||||||
|
|
||||||
|
|
||||||
|
debug : Command
|
||||||
|
debug =
|
||||||
|
{ name = "debug"
|
||||||
|
, opts = []
|
||||||
|
, flags = []
|
||||||
|
, flagOpts = []
|
||||||
|
}
|
||||||
|
|> mkCommand
|
||||||
|
|
||||||
|
|
||||||
|
environment : Command
|
||||||
|
environment =
|
||||||
|
{ name = "environment"
|
||||||
|
, opts =
|
||||||
|
[ { name = "show" }
|
||||||
|
]
|
||||||
|
, flags = []
|
||||||
|
, flagOpts =
|
||||||
|
[ { name = "--theme" }
|
||||||
|
, { name = "--fontsize" }
|
||||||
|
, { name = "--prompt" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|> mkCommand
|
||||||
|
|
||||||
|
|
||||||
|
hello : Command
|
||||||
|
hello =
|
||||||
|
{ name = "hello"
|
||||||
|
, opts = []
|
||||||
|
, flags = []
|
||||||
|
, flagOpts = []
|
||||||
|
}
|
||||||
|
|> mkCommand
|
||||||
|
|
||||||
|
|
||||||
|
todo : Command
|
||||||
|
todo =
|
||||||
|
{ name = "todo"
|
||||||
|
, opts = []
|
||||||
|
, flags = []
|
||||||
|
, flagOpts = []
|
||||||
|
} |> mkCommand
|
||||||
|
|
31
src/ElmTypes.elm
Normal file
31
src/ElmTypes.elm
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
module ElmTypes exposing (Model)
|
||||||
|
|
||||||
|
import Browser
|
||||||
|
import Browser.Navigation as Nav
|
||||||
|
import Cli
|
||||||
|
import Json.Encode as E
|
||||||
|
import Url
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ key : Nav.Key
|
||||||
|
, url : Url.Url
|
||||||
|
, theme : Theme
|
||||||
|
, font : Font
|
||||||
|
, cookiesKept : CookiesKept
|
||||||
|
, prompt : Prompt
|
||||||
|
, content : List (Html Msg)
|
||||||
|
, cliContent : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= LinkClicked Browser.UrlRequest
|
||||||
|
| UrlChanged Url.Url
|
||||||
|
| TakeInput String
|
||||||
|
| NoInitFocus
|
||||||
|
| ReceivedStorage E.Value
|
||||||
|
|
||||||
|
|
||||||
|
type alias CommandRunner =
|
||||||
|
Model -> List String -> ( Model, Cmd Msg )
|
852
src/Main.elm
852
src/Main.elm
File diff suppressed because it is too large
Load diff
37
src/Types.elm
Normal file
37
src/Types.elm
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
module Types exposing (..)
|
||||||
|
|
||||||
|
import Browser
|
||||||
|
import Browser.Navigation
|
||||||
|
import Cli
|
||||||
|
import ElmskellTypes.Generated.Types exposing (..)
|
||||||
|
import Html.Styled
|
||||||
|
import Json.Encode
|
||||||
|
import Url
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= LinkClicked Browser.UrlRequest
|
||||||
|
| UrlChanged Url.Url
|
||||||
|
| TakeInput String
|
||||||
|
| NoInitFocus
|
||||||
|
| ReceivedStorage Json.Encode.Value
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ key : Browser.Navigation.Key
|
||||||
|
, url : Url.Url
|
||||||
|
, theme : Theme
|
||||||
|
, font : Font
|
||||||
|
, cookiesKept : CookiesKept
|
||||||
|
, prompt : Prompt
|
||||||
|
, content : List (Html.Styled.Html Msg)
|
||||||
|
, cliContent : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias CommandRunner_ =
|
||||||
|
Model -> List String -> ( Model, Cmd Msg )
|
||||||
|
|
||||||
|
|
||||||
|
type alias CommandRunner =
|
||||||
|
Model -> Cli.FilledCommand -> ( Model, Cmd Msg )
|
Loading…
Add table
Add a link
Reference in a new issue