WIP on upgrading to 0.15

This commit is contained in:
Paul Chiusano 2015-05-04 17:38:24 -04:00
parent 5e518c9c39
commit cf8abfd2a5
28 changed files with 293 additions and 422 deletions

View File

@ -1,6 +1,6 @@
{
"version": "1.0.0",
"summary": "w00t",
"summary": "Front-end for the Unison editor",
"repository": "https://github.com/USER/PROJECT.git",
"license": "MIT",
"source-directories": [
@ -8,9 +8,9 @@
],
"exposed-modules": ["Messages"],
"native-modules" : true,
"elm-version" : "0.15.0 <= v < 0.16.0",
"dependencies": {
"elm-lang/core" : "1.0.0 <= v < 2.0.0",
"Dandandan/Easing" : "1.0.1 <= v < 2.0.0",
"Dandandan/parser" : "5.0.1 <= v < 6.0.0"
"elm-lang/core" : "2.0.0 <= v < 3.0.0",
"evancz/elm-http" : "1.0.0 <= v < 2.0.0"
}
}

View File

@ -2,10 +2,10 @@ module Elmz.Json.Decoder where
import Dict as M
import Json.Decode as J
import Json.Decode (Decoder, andThen)
import Json.Decode exposing (Decoder, andThen)
import List
import Set
import Set (Set)
import Set exposing (Set)
import String as S
type alias Decoder a = J.Decoder a

View File

@ -1,27 +1,31 @@
module Elmz.Json.Request where
import Elmz.Json.Encoder (Encoder)
import Elmz.Json.Encoder exposing (Encoder)
import Elmz.Json.Encoder as Encoder
import Elmz.Json.Decoder (Decoder)
import Elmz.Json.Decoder exposing (Decoder)
import Elmz.Json.Decoder as Decoder
import Elmz.Signal as Signals
import Http
import Maybe
import Result
import Signal
import Task exposing (Task)
import Time
type alias Request a b =
{ encoder : a -> Http.Request String
{ encoder : a -> Out String
, decoder : Decoder b }
type alias Out a = { verb : String, url : String, body : a }
type alias Host = String
type alias Path = String
type Status e = Inactive | Waiting | Failed e
post : Host -> Path -> Encoder a -> Decoder b -> Request a b
post host path e d = Request (jsonPost e host path) d
post host path e d =
let out a = Out "POST" (host ++ "/" ++ path) (Encoder.render e a)
in Request out d
contramap : (a0 -> a) -> Request a b -> Request a0 b
contramap f r = { r | encoder <- r.encoder << f }
@ -32,35 +36,7 @@ map f r = { r | decoder <- Decoder.map f r.decoder }
to : Request a b -> (b -> c) -> Request a c
to r f = map f r
send : Request a b -> a -> Signal (Maybe a) -> Signal (Result (Status String) b)
send r az ma =
let a = Signals.justs ma |> Signal.map (Maybe.withDefault az)
waitings = Signal.map (always (Result.Err Waiting)) a
results = Http.send (Signal.map r.encoder a) |> Signal.map (decodeResponse r.decoder)
inactives = Signal.map (always (Result.Err Inactive)) (Time.delay 0 results)
in results `Signal.merge` inactives `Signal.merge` waitings
isWaiting : Signal (Result (Status String) a) -> Signal Bool
isWaiting results =
let f r = case r of
Result.Err Waiting -> True
_ -> False
in Signal.map f results
jsonGet : Encoder a -> Host -> String -> a -> Http.Request String
jsonGet = jsonRequest "GET"
jsonPost : Encoder a -> Host -> String -> a -> Http.Request String
jsonPost = jsonRequest "POST"
jsonRequest : String -> Encoder a -> Host -> String -> a -> Http.Request String
jsonRequest verb ja host path a =
Http.request verb (host ++ "/" ++ path) (Encoder.render ja a) [("Content-Type", "application/json")]
decodeResponse : Decoder a -> Http.Response String -> Result (Status String) a
decodeResponse p r = case r of
Http.Success body -> case Decoder.decodeString p body of
Result.Err e -> Result.Err (Failed e)
Result.Ok a -> Result.Ok a
Http.Waiting -> Result.Err Waiting
Http.Failure code body -> Result.Err <| Failed ("error " ++ toString code ++ "\n" ++ body)
sendPost : Request a b -> a -> Task Http.Error b
sendPost r a =
let out = r.encoder a
in Http.post r.decoder out.url (Http.string out.body)

View File

@ -1,12 +1,11 @@
module Elmz.Layout where
import Array (Array)
import Array exposing (Array)
import Color
import Color (Color)
import Graphics.Element (Direction, Element, Position)
import Color exposing (Color)
import Graphics.Element exposing (Direction, Element, Position)
import Graphics.Element as E
import List
import List ((::))
import Maybe
type alias Pt = { x : Int, y: Int }
@ -147,7 +146,7 @@ fill c e = container (tag e) (widthOf e) (heightOf e) (Pt 0 0) e
row : List (Layout k) -> List (Layout k)
row ls = case ls of
[] -> []
_ -> let maxh = List.maximum (List.map heightOf ls)
_ -> let maxh = Maybe.withDefault 0 (List.maximum (List.map heightOf ls))
cell e = let diff = maxh - heightOf e
in if diff == 0 then e
else container (tag e) (widthOf e) maxh (Pt 0 (toFloat diff / 2 |> floor)) e
@ -156,7 +155,7 @@ row ls = case ls of
column : List (Layout k) -> List (Layout k)
column ls = case ls of
[] -> []
_ -> let maxw = List.maximum (List.map widthOf ls)
_ -> let maxw = Maybe.withDefault 0 (List.maximum (List.map widthOf ls))
cell e = let diff = maxw - widthOf e
in if diff == 0 then e
else container (tag e) maxw (heightOf e) (Pt (toFloat diff / 2 |> floor) 0) e
@ -165,7 +164,7 @@ column ls = case ls of
leftAlignedColumn : List (Layout k) -> List (Layout k)
leftAlignedColumn ls = case ls of
[] -> []
_ -> let maxw = List.maximum (List.map widthOf ls)
_ -> let maxw = Maybe.withDefault 0 (List.maximum (List.map widthOf ls))
cell e = let diff = maxw - widthOf e
in if diff == 0 then e
else container (tag e) maxw (heightOf e) (Pt 0 0) e

View File

@ -2,7 +2,7 @@ module Elmz.Matcher where
import Debug
import Elmz.Moore as Moore
import Elmz.Moore (Moore(..))
import Elmz.Moore exposing (Moore(..))
import List
import String
@ -39,7 +39,7 @@ model matches =
out = List.filter (matches q.string) (q.values ++ r.values)
-- tricky part is determining whether we need to do another search
full = r.additionalResults <= 0
lastExamined = List.maximum (-1 :: r.positionsExamined)
lastExamined = Maybe.withDefault (-1) (List.maximum r.positionsExamined)
ok =
-- we already have results for this query
r.query == q.string ||

View File

@ -1,8 +1,7 @@
module Elmz.Moore where
import Signal
import Signal ((<~), (~), foldp, Signal)
import List ((::))
import Signal exposing ((<~), (~), foldp, Signal)
import Maybe
type Moore i o = Moore o (i -> Maybe (Moore i o))
@ -104,46 +103,5 @@ transform m i =
let s i m = feed i m
in extract <~ foldp s m i
{-| Unlike `transform`, only emits events when the input transitions to a new state. -}
transitions : Moore i o -> Signal i -> Signal o
transitions m i =
let s i (m,_) = case step i m of
Nothing -> (m, False)
Just m2 -> (m2, True)
states = foldp s (m, True) i
changes = Signal.map snd states
in Signal.keepWhen changes (extract m) ((extract << fst) <~ states)
unit : o -> Moore i o
unit o = Moore o (always Nothing)
{-
withInput : i -> Moore i o -> Moore i (i,o)
withInput i0 m = map2 (,) (echo i0) m
dropRepeats : o -> Moore o o
dropRepeats prev = Moore ((==) prev) prev dropRepeats
foldResult : (a -> r) -> (b -> r) -> Result a b -> r
foldResult f1 f2 e = case e of
Err a -> f1 a
Ok b -> f2 b
either : Moore a (Result x y) -> Moore x b -> Moore y b -> Moore a b
either (Moore samei xy ki) left right =
let same a = samei a && foldResult (steady left) (steady right) xy
st a = case xy of
Err x -> either (ki a) (step left x) right
Ok y -> either (ki a) left (step right y)
o = case xy of
Err x -> extract left
Ok y -> extract right
in Moore same o st
{-| Run the first argument until it emits `Err s`, then switch permanently to `f s`. -}
bind : Moore a (Result s b) -> (s -> Moore a b) -> Moore a b
bind (Moore same sb k) f = case sb of
Err s -> f s
Ok b -> Moore same b (\a -> bind (k a) f)
-}

View File

@ -1,7 +1,7 @@
module Elmz.Movement where
import Keyboard
import Signal ((<~), (~), Signal)
import Signal exposing ((<~), (~), Signal)
import Signal
import Elmz.Signal as Signals
import Time

138
editor/src/Elmz/Parser.elm Normal file
View File

@ -0,0 +1,138 @@
module Elmz.Parser where
import String
import Regex
type alias Msg = List String
type alias Status = { message : Msg, committed : Bool }
type alias Parser a = { string : String, offset : Int } -> Result Status (a, Int)
parse : Parser a -> String -> Result String a
parse p s = case p { string = s, offset = 0 } of
Err e -> Err (String.join "\n" e.message)
Ok (a,_) -> Ok a
unit : a -> Parser a
unit a _ = Ok (a, 0)
fail : Parser a
fail s = Err { message = [], committed = False }
map : (a -> b) -> Parser a -> Parser b
map f p s = case p s of
Ok (a, consumed) -> Ok (f a, consumed)
Err e -> Err e
(<$>) : (a -> b) -> Parser a -> Parser b
(<$>) = map
-- note: implementation not stack safe
many : Parser a -> Parser (List a)
many a s = case a s of
Err e -> if e.committed then Err e else Ok ([],0)
Ok (hd,consumed) -> case many a { s | offset <- s.offset + consumed } of
Err e -> Err e
Ok (tl,consumedTl) -> Ok (hd :: tl, consumed + consumedTl)
some : Parser a -> Parser (List a)
some a = (::) <$> a <*> many a
andThen : Parser a -> (a -> Parser b) -> Parser b
andThen p f s = case p s of
Err e -> Err e
Ok (a, consumed) ->
(if consumed > 0 then commit else identity) (f a) { s | offset <- s.offset + consumed }
commit : Parser a -> Parser a
commit p s = case p s of
Err e -> Err { e | committed <- True }
r -> r
attempt : Parser a -> Parser a
attempt p s = case p s of
Err e -> Err { e | committed <- False }
Ok a -> Ok a
scope : String -> Parser a -> Parser a
scope lbl p s = case p s of
Err e -> Err { e | message <- lbl :: e.message }
Ok a -> Ok a
label : String -> Parser a -> Parser a
label lbl p s = case p s of
Err e -> Err { e | message <- [lbl] }
Ok a -> Ok a
or : Parser a -> Parser a -> Parser a
or p p2 s = case p s of
Ok a -> Ok a
Err e -> if e.committed then Err e else p2 s
choice : List (Parser a) -> Parser a
choice = List.foldr or fail
ap : Parser (a -> b) -> Parser a -> Parser b
ap f a = f `andThen` \f -> map f a
satisfy : (Char -> Bool) -> Parser String
satisfy f s =
let sub = String.slice s.offset ((String.length s.string) `max` (s.offset + 1)) s.string
in if String.all f sub then Ok (sub, 1) else Err { message = [], committed = False }
symbol : Char -> Parser String
symbol c = satisfy ((==) c)
token : String -> Parser String
token t s =
if String.startsWith t (String.dropLeft s.offset s.string)
then Ok (t, String.length t)
else Err { message = ["expected " ++ t], committed = False }
reset : { string : String, offset : Int } -> { string : String, offset : Int }
reset s = { string = String.dropLeft s.offset s.string, offset = 0 }
digits : Parser String
digits = regex "\\d+"
nonnegativeInt : Parser Int
nonnegativeInt = digits `andThen` \s -> case String.toInt s of
Err e -> label e fail
Ok n -> unit n
int : Parser Int
int = optional (symbol '-') `andThen` \sign -> case sign of
Nothing -> nonnegativeInt
Just _ -> map negate nonnegativeInt
float : Parser Float
float = regex "[+-]?\\d+\\.\\d+" `andThen` \s -> case String.toFloat s of
Err e -> label e fail
Ok n -> unit n
optional : Parser a -> Parser (Maybe a)
optional p = map Just p `or` unit Nothing
regex : String -> Parser String
regex r s = let compiled = Regex.regex r in case reset s of
s -> case List.map .match (Regex.find (Regex.AtMost 1) compiled s.string) of
[] -> Err { message = [], committed = False }
hd :: _ -> Ok (hd, String.length hd)
infixl 4 <*>
infixl 4 <*
infixl 4 *>
infixl 4 <$
infixl 4 <$>
(<*>) : Parser (a -> b) -> Parser a -> Parser b
(<*>) = ap
(<*) : Parser a -> Parser b -> Parser a
a <* b = unit always <*> a <*> b
(<$) : a -> Parser b -> Parser a
a <$ p = map (always a) p
(*>) : Parser a -> Parser b -> Parser b
a *> b = unit (\_ b -> b) <*> a <*> b

View File

@ -1,13 +1,13 @@
{-| One-dimensional selection model. -}
module Elmz.Selection1D where
import Elmz.Layout (Containment, Layout, Region)
import Elmz.Layout exposing (Containment, Layout, Region)
import Elmz.Layout as Layout
import Elmz.Movement as Movement
import Elmz.Moore (Moore(..))
import Elmz.Moore exposing (Moore(..))
import Elmz.Moore as Moore
import Elmz.Signal as Signals
import Graphics.Element (Element)
import Graphics.Element exposing (Element)
import Graphics.Element as Element
import Maybe
import Result

View File

@ -5,37 +5,20 @@ import Debug
import Elmz.Maybe
import Keyboard
import List
import List ((::))
import Maybe
import Execute
import Mouse
import Result
import Set
import Signal (..)
import Set exposing (Set)
import Signal exposing (..)
import Text
import Time
import Time (Time)
import Time exposing (Time)
{-| Accumulates into a list using `foldp` during regions where `cond`
is `True`, otherwise emits the empty list. -}
accumulateWhen : Signal Bool -> Signal a -> Signal (List a)
accumulateWhen cond a = foldpWhen cond (::) [] a |> map List.reverse
asyncUpdate : (Signal req -> Signal (model -> (Maybe req, model)))
-> Signal (model -> (Maybe req, model))
-> req
-> model
-> Signal model
asyncUpdate responseActions actions req0 model0 =
let reqs = channel req0
mergedActions = merge actions (responseActions (subscribe reqs))
step action (_,model) =
let (req, model') = action model
in (Maybe.map (send reqs) req, model')
modelsWithMsgs = foldp step (Nothing,model0) mergedActions
msgs = Execute.schedule (map (Maybe.withDefault Execute.noop) (justs (map fst modelsWithMsgs)))
in during (map snd modelsWithMsgs) msgs
{-| Alternate sending `input` through `left` or `right` signal transforms,
merging their results. -}
alternate : (Signal (Maybe a) -> Signal c)
@ -63,7 +46,7 @@ delay h s =
{-| Only emit when the input signal transitions from `True` to `False`. -}
downs : Signal Bool -> Signal Bool
downs s = dropIf identity True s
downs s = filter not True s
{-| Emits an event whenever there are two events that occur within `within` time of each other. -}
doubleWithin : Time -> Signal s -> Signal ()
@ -73,7 +56,7 @@ doubleWithin within s =
Nothing -> False
Just t1 -> if t2 - t1 < within then True else False
in map2 f (delay Nothing (map Just ts)) ts
|> keepIf identity False
|> filter identity False
|> map (always ())
{-| Evaluate the second signal for its effects, but return the first signal. -}
@ -141,7 +124,7 @@ flattenMaybe s = fromMaybe (constant Nothing) s
{-| Ignore any events of `Nothing`. -}
justs : Signal (Maybe a) -> Signal (Maybe a)
justs s = keepIf (Maybe.map (always True) >> Maybe.withDefault False) Nothing s
justs s = filter (Maybe.map (always True) >> Maybe.withDefault False) Nothing s
{-| Event which fires with the given `a` whenever the keycode is pressed down. -}
keyEvent : a -> Int -> Signal a
@ -151,20 +134,12 @@ keyEvent k code = map (always k) (ups (Keyboard.isDown code))
keyChordEvent : a -> List Keyboard.KeyCode -> Signal a
keyChordEvent k codes =
let
hazTehCodez : List Keyboard.KeyCode -> Bool
hazTehCodez : Set Keyboard.KeyCode -> Bool
hazTehCodez pressed =
let pressed' = Set.fromList pressed
in List.all (\k -> Set.member k pressed') codes
List.all (\k -> Set.member k pressed) codes
in
map (always k) (ups (map hazTehCodez Keyboard.keysDown))
loop : (Signal a -> Signal s -> Signal (b,s)) -> s -> Signal a -> Signal b
loop f s a =
let chan = channel s
bs = f a (sampleOn a (subscribe chan)) -- Signal (b,s)
in map2 always (map fst bs)
(Execute.complete (map (\(_,s) -> send chan s) bs))
map2r : (a -> b -> c) -> Signal a -> Signal b -> Signal c
map2r f a b = sampleOn b (map2 f a b)
@ -172,39 +147,6 @@ map2r f a b = sampleOn b (map2 f a b)
mask : Signal Bool -> Signal a -> Signal (Maybe a)
mask = map2 (\b a -> if b then Just a else Nothing)
{-| Merge two signals, using the combining function if any events co-occcur. -}
mergeWith : (a -> a -> a) -> Signal a -> Signal a -> Signal a
mergeWith resolve left right =
let boolLeft = always True <~ left
boolRight = always False <~ right
bothUpdated = (/=) <~ merge boolLeft boolRight ~ merge boolRight boolLeft
exclusive = dropWhen bothUpdated Nothing (Just <~ merge left right)
overlap = keepWhen bothUpdated Nothing (Just <~ map2 resolve left right)
combine m1 m2 = case Maybe.oneOf [m1, m2] of
Just a -> a
Nothing -> List.head [] -- impossible
in combine <~ exclusive ~ overlap
{-| Merge two signals, composing the functions if any events co-occcur. -}
mergeWithBoth : Signal (a -> a) -> Signal (a -> a) -> Signal (a -> a)
mergeWithBoth = mergeWith (>>)
{-| Merge the two signals. If events co-occur, emits `(Just a, Just b)`,
otherwise emits `(Just a, Nothing)` or `(Nothing, Just b)`. -}
oneOrBoth : Signal a -> Signal b -> Signal (Maybe a, Maybe b)
oneOrBoth a b =
let combine a b = case a of
(Nothing,_) -> b
(Just a,_) -> case b of
(_, Nothing) -> (Just a, Nothing)
(_, Just b) -> (Just a, Just b)
in mergeWith combine (map (\a -> (Just a, Nothing)) a)
(map (\b -> (Nothing, Just b)) b)
{-| A signal which emits a single event after a specified time. -}
pulse : Time -> Signal ()
pulse time = Time.delay time start
{-| Replace the first occurence of the input signal with `a`. -}
replaceFirst : a -> Signal a -> Signal a
replaceFirst a0 s =
@ -212,37 +154,21 @@ replaceFirst a0 s =
f replace a = if replace then Debug.log ("replacing " ++ toString a) a0 else a
in map2 f first s
{-| Emit updates to `s` only when it moves outside the current bin,
according to the function `within`. Otherwise emit no update but
take on the value `Nothing`. -}
quantize : (a -> r -> Bool) -> Signal r -> Signal a -> Signal (Maybe a)
quantize within bin s =
let f range a = if a `within` range then Nothing else Just a
in dropIf (Maybe.map (always False) >> Maybe.withDefault True) Nothing (f <~ bin ~ s)
{-| Repeat updates to a signal after it has remained steady for `t`
elapsed time, and only if the current value tests true against `f`. -}
repeatAfterIf : Time -> number -> (a -> Bool) -> Signal a -> Signal a
repeatAfterIf time fps f s =
let repeatable = map f s
delayedRep = repeatable |> keepIf identity False |> Time.since time |> map not
delayedRep = repeatable |> filter identity False |> Time.since time |> map not
resetDelay = merge (always False <~ s) delayedRep
repeats = Time.fpsWhen fps ((&&) <~ repeatable ~ dropRepeats resetDelay)
in sampleOn repeats s
{-| A signal which emits a single event on or immediately after program start. -}
start : Signal ()
start =
let chan = channel ()
msg = send chan ()
in sampleOn (subscribe chan)
(map2 always (constant ()) (Execute.schedule (constant msg)))
{-| Only emit updates of `s` when it settles into a steady state with
no updates within the period `t`. Useful to avoid propagating updates
when a value is changing too rapidly. -}
steady : Time -> Signal a -> Signal a
steady t s = sampleOn (Time.since t s |> dropIf identity False) s
steady t s = sampleOn (Time.since t s |> filter not False) s
{-| Like `sampleOn`, but the output signal refreshes whenever either signal updates. -}
sampleOnMerge : Signal a -> Signal b -> Signal b
@ -279,7 +205,7 @@ unchanged a = map not (changed a)
{-| Only emit when the input signal transitions from `False` to `True`. -}
ups : Signal Bool -> Signal Bool
ups s = keepIf identity False s
ups s = filter identity False s
zip : Signal a -> Signal b -> Signal (a,b)
zip = map2 (,)

View File

@ -1,38 +0,0 @@
module Execute where
{-| Execute scheduling and delivery of `Signal.Message` values. -}
import Native.Execute
import Signal (Signal, Message)
{-| The message which does nothing. -}
noop : Message
noop = Native.Execute.noop
{-| Combine two messages into one. The first argument will
be delivered before the second. -}
combine : Message -> Message -> Message
combine = Native.Execute.combine
{-| Schedule the input `Message` values for delivery.
The output signal has same event occurrences as the input signal,
and there is no guarantee that effects of message delivery will
be visible when the output `Signal ()` updates.
Implementation uses `setTimeout(.., 0)` in Javascript to schedule
delivery of the `Message`.
-}
schedule : Signal Message -> Signal ()
schedule = Native.Execute.schedule
{-| Schedule the input `Message` values for delivery and wait for
completion of each delivery. Unlike `schedule`, the output `Signal`
will refresh once per `Message` _after_ all effects of message
delivery have propagated through the signal graph. There will be
exactly one refresh of the output signal for each input `Message`,
but the implementation uses `setTimeout(.., 0)` in Javascript so
there aren't any guarantees about exact ordering of updates,
especially with regard to other events in the signal graph.
-}
complete : Signal Message -> Signal ()
complete = Native.Execute.complete

View File

@ -1,59 +0,0 @@
Elm.Native.Execute = {};
Elm.Native.Execute.make = function(localRuntime) {
localRuntime.Native = localRuntime.Native || {};
localRuntime.Native.Execute = localRuntime.Native.Execute || {};
if (localRuntime.Native.Execute.values) {
return localRuntime.Native.Execute.values;
}
var Signal = Elm.Signal.make(localRuntime);
function combine(thunk1, thunk2) {
return function() {
setTimeout(
function() {
thunk1();
setTimeout(thunk2, 0);
},
0);
}
}
// schedule : Signal Message -> Signal ()
function schedule(msgs) {
var tuple0 = { ctor: "_Tuple0" };
function scheduleForce(thunk) {
setTimeout(thunk, 0);
return tuple0;
}
return A2( Signal.map, scheduleForce, msgs );
}
// complete : Signal Message -> Signal ()
function complete(msgs) {
var tuple0 = { ctor: "_Tuple0" };
var output = Signal.constant(tuple0);
// need to nest the calls to `setTimeout` to ensure the output signal
// is refreshed *after* the message has been delivered
function scheduleForce(thunk) {
setTimeout(
function() {
thunk();
setTimeout(function() { localRuntime.notify(output.id, tuple0); }, 0)
}, 0);
return tuple0;
}
var forced = A2( Signal.map, scheduleForce, msgs );
function k(x) { return function(y) { return x; } }
// the sampleOn output is important, since the `map2` would otherwise
// emit an event when either a message comes in OR a message is delivered
return A2(Signal.sampleOn, output, A3( Signal.map2, k, output, forced));
}
return localRuntime.Native.Execute.values = {
schedule: schedule,
complete: complete,
combine: combine,
noop: function() {}
};
};

View File

@ -1,10 +1,10 @@
module Unison.Action where
import Elmz.Json.Encoder as Encoder
import Elmz.Json.Encoder (Encoder)
import Elmz.Json.Encoder exposing (Encoder)
import Elmz.Json.Decoder as Decoder
import Elmz.Json.Decoder (Decoder)
import Unison.Symbol (Symbol)
import Elmz.Json.Decoder exposing (Decoder)
import Unison.Symbol exposing (Symbol)
import Unison.Symbol as Symbol
type Action

View File

@ -2,25 +2,25 @@ module Unison.EditableTerm where
import Debug
import Elmz.Layout as Layout
import Elmz.Layout (Layout,Region)
import Elmz.Moore (Moore(..))
import Elmz.Layout exposing (Layout,Region)
import Elmz.Moore exposing (Moore(..))
import Elmz.Moore as Moore
import Elmz.Movement as Movement
import Elmz.Trie as Trie
import Elmz.Trie (Trie)
import Elmz.Trie exposing (Trie)
import Graphics.Element as Element
import Graphics.Element (Element)
import Graphics.Element exposing (Element)
import List
import Maybe
import Unison.Path as Path
import Unison.Path (Path)
import Unison.Reference (Reference)
import Unison.Metadata (Metadata)
import Unison.Path exposing (Path)
import Unison.Reference exposing (Reference)
import Unison.Metadata exposing (Metadata)
import Unison.Metadata as Metadata
import Unison.Scope as Scope
import Unison.Styles as Styles
import Unison.Term as Term
import Unison.Term (Term)
import Unison.Term exposing (Term)
import Unison.View as View
import Unison.Node as Node

View File

@ -1,16 +1,15 @@
module Unison.Editor where
import Debug
import Execute
import Elmz.Json.Request as JR
import Elmz.Layout (Containment(Inside,Outside), Layout, Pt, Region)
import Elmz.Layout exposing (Containment(Inside,Outside), Layout, Pt, Region)
import Elmz.Layout as Layout
import Elmz.Moore (Moore(..))
import Elmz.Moore exposing (Moore(..))
import Elmz.Moore as Moore
import Elmz.Movement as Movement
import Elmz.Selection1D as Selection1D
import Elmz.Signal as Signals
import Graphics.Element (Element)
import Graphics.Element exposing (Element)
import Graphics.Element as Element
import Graphics.Input.Field as Field
import Maybe
@ -21,21 +20,21 @@ import Signal
import Unison.Action as Action
import Unison.EditableTerm as EditableTerm
import Unison.SearchboxParser as SearchboxParser
import Unison.Hash (Hash)
import Unison.Metadata (Metadata)
import Unison.Hash exposing (Hash)
import Unison.Metadata exposing (Metadata)
import Unison.Metadata as Metadata
import Unison.Node as Node
import Unison.Path (Path)
import Unison.Path exposing (Path)
import Unison.Path as Path
import Unison.Reference (Reference)
import Unison.Reference exposing (Reference)
import Unison.Reference as Reference
import Unison.Scope as Scope
import Unison.Styles as Styles
import Unison.Term (Term)
import Unison.Term exposing (Term)
import Unison.Term as Term
import Unison.TermExplorer as TermExplorer
import Unison.Terms as Terms
import Unison.Type (Type)
import Unison.Type exposing (Type)
import Unison.Type as Type
import Unison.View as View
import Window
@ -205,7 +204,7 @@ model sink term0 =
ignoreUpDown : Signal Field.Content -> Signal Field.Content
ignoreUpDown s =
let k = Signal.sampleOn (Signal.keepIf (\a -> a.y /= 0) {x = 0, y = 0} Keyboard.arrows)
let k = Signal.sampleOn (Signal.filter (\a -> a.y /= 0) {x = 0, y = 0} Keyboard.arrows)
(Signals.delay Field.noContent s)
in Signal.merge k s

View File

@ -1,9 +1,9 @@
module Unison.Hash where
import Json.Decode as Decode
import Json.Decode (Decoder)
import Json.Decode exposing (Decoder)
import Elmz.Json.Encoder as Encoder
import Elmz.Json.Encoder (Encoder)
import Elmz.Json.Encoder exposing (Encoder)
type alias Hash = String

View File

@ -2,19 +2,19 @@ module Unison.Metadata where
import Array
import Dict
import Elmz.Json.Decoder (Decoder, (#))
import Elmz.Json.Decoder exposing (Decoder, (#))
import Elmz.Json.Decoder as Decoder
import Elmz.Json.Encoder (Encoder)
import Elmz.Json.Encoder exposing (Encoder)
import Elmz.Json.Encoder as Encoder
import Elmz.Moore (Moore(..))
import Elmz.Moore exposing (Moore(..))
import Elmz.Moore as Moore
import List
import Maybe
import Unison.Hash as H
import Unison.Path (Path)
import Unison.Path exposing (Path)
import Unison.Path as Path
import Unison.Reference as R
import Unison.Symbol (Symbol)
import Unison.Symbol exposing (Symbol)
import Unison.Symbol as Symbol
type alias E = Path.E
type alias Path = Path.Path -- to avoid conflict with Graphics.Collage.Path
@ -49,9 +49,7 @@ firstSymbol defaultName md = case md.names of
firstName : String -> Metadata -> String
firstName ifEmpty md =
if List.isEmpty md.names
then ifEmpty
else (List.head md.names).name
Maybe.withDefault ifEmpty (Maybe.map .name (List.head md.names))
type alias Names = List Symbol

View File

@ -4,25 +4,25 @@ module Unison.Node where
import Dict as M
import Maybe
import Elmz.Json.Encoder as Encoder
import Elmz.Json.Encoder (Encoder)
import Elmz.Json.Encoder exposing (Encoder)
import Elmz.Json.Decoder as Decoder
import Elmz.Json.Decoder (Decoder)
import Elmz.Json.Request (Request)
import Elmz.Json.Decoder exposing (Decoder)
import Elmz.Json.Request exposing (Request)
import Elmz.Json.Request as Request
import Set as S
import Signal
import Signal ((<~),(~),Signal)
import Signal exposing ((<~),(~),Signal)
import Unison.Action as A
import Unison.Action (Action)
import Unison.Action exposing (Action)
import Unison.Metadata as MD
import Unison.Metadata (Metadata, Query)
import Unison.Metadata exposing (Metadata, Query)
import Unison.Term as E
import Unison.Path as Path
import Unison.Reference as Reference
import Unison.Reference (Reference)
import Unison.Term (Term)
import Unison.Reference exposing (Reference)
import Unison.Term exposing (Term)
import Unison.Type as T
import Unison.Type (Type)
import Unison.Type exposing (Type)
type alias Path = Path.Path
type alias Host = String

View File

@ -1,14 +1,13 @@
module Unison.Path where
import Array (Array)
import Array exposing (Array)
import Array as A
import Elmz.Json.Decoder as Decoder
import Elmz.Json.Encoder (Encoder)
import Elmz.Json.Encoder exposing (Encoder)
import Elmz.Json.Encoder as Encoder
import Json.Decode (Decoder)
import Json.Decode exposing (Decoder)
import Json.Decode as Decode
import List
import List ((::))
import String
type E

View File

@ -1,14 +1,14 @@
module Unison.Reference where
import Dict (Dict)
import Dict exposing (Dict)
import Dict
import Elmz.Json.Encoder as Encoder
import Elmz.Json.Encoder (Encoder)
import Elmz.Json.Encoder exposing (Encoder)
import Elmz.Json.Decoder as Decoder
import Elmz.Json.Decoder (Decoder)
import Elmz.Json.Decoder exposing (Decoder)
import List
import String
import Unison.Hash (Hash)
import Unison.Hash exposing (Hash)
import Unison.Hash as H
type Reference

View File

@ -1,19 +1,18 @@
module Unison.Scope where
import Debug
import Elmz.Layout (Region, Layout)
import Elmz.Layout exposing (Region, Layout)
import Elmz.Layout as Layout
import Elmz.Signal as Signals
import Elmz.Movement as Movement
import Graphics.Element (Element)
import Graphics.Element exposing (Element)
import Graphics.Element as Element
import List
import List ((::))
import Maybe
import Signal
import Unison.Path as Path
import Unison.Styles as Styles
import Unison.Term (Term)
import Unison.Term exposing (Term)
import Unison.Term as Term
import Unison.View as View

View File

@ -2,20 +2,18 @@ module Unison.SearchboxParser where
import Debug
import Elmz.Distance as Distance
import Elmz.Distance (Distance)
import Elmz.Distance exposing (Distance)
import List
import Parser
import Parser (Parser, (<*), (*>), (<*>), (<$>), (<$))
import Parser.Number
import Parser.Char
import Elmz.Parser as Parser
import Elmz.Parser exposing (Parser, (<*), (*>), (<*>), (<$>), (<$))
import Unison.Term as Term
import Unison.Term (Term)
import Unison.Term exposing (Term)
import String
import Set
parser : { literal : Term -> a
, query : String -> a
, combine : a -> Char -> a }
, combine : a -> String -> a }
-> Parser a
parser env =
let lit = Parser.map env.literal literal
@ -32,14 +30,14 @@ space = Parser.satisfy ((==) ' ')
parse :
{ literal : Term -> a
, query : String -> a
, combine : a -> Char -> a }
, combine : a -> String -> a }
-> String -> Result String a
parse env = Parser.parse (parser env)
parseTerm : String -> Result String Term
parseTerm = Parser.parse literal
operator : Parser Char
operator : Parser String
operator =
let ops = Set.fromList (String.toList "!@#$%^&*-+|\\;.></`~")
in Parser.satisfy (\c -> Set.member c ops)
@ -55,13 +53,13 @@ blank : Parser Term
blank = Parser.map (always Term.Blank) (Parser.symbol '_')
int : Parser Term
int = Parser.map (Term.Lit << Term.Number << toFloat) Parser.Number.integer
int = Parser.map (Term.Lit << Term.Number << toFloat) (Parser.attempt Parser.int)
float : Parser Term
float = Parser.map (Term.Lit << Term.Number) Parser.Number.float
float = Parser.map (Term.Lit << Term.Number) (Parser.attempt Parser.float)
string : Parser Term
string = Parser.Char.between quote quote (until quote)
string = (Parser.symbol quote *> (until quote) <* Parser.symbol quote)
|> Parser.map (Term.Lit << Term.Text)
openString : Parser Term
@ -77,22 +75,20 @@ distance =
pixels : Parser Distance
pixels =
let f n = Distance.Scale (toFloat n) Distance.Pixel
in f <$> Parser.Number.natural <* Parser.token "px"
in f <$> Parser.nonnegativeInt <* Parser.token "px"
fraction : Parser Distance
fraction = Parser.symbol '1'
*> Parser.symbol '/'
*> (Parser.Number.natural <* Parser.symbol 'd')
*> (Parser.nonnegativeInt <* Parser.symbol 'd')
|> Parser.map (\denominator -> Distance.Fraction (1.0 / toFloat denominator))
quote = '"' -- "
until : Char -> Parser String
until c =
Parser.map (String.concat << List.map String.fromChar)
(Parser.many (Parser.satisfy ((/=) c)))
Parser.map String.concat (Parser.many (Parser.satisfy ((/=) c)))
until1 : Char -> Parser String
until1 c =
Parser.map (String.concat << List.map String.fromChar)
(Parser.some (Parser.satisfy ((/=) c)))
Parser.map String.concat (Parser.some (Parser.satisfy ((/=) c)))

View File

@ -1,20 +1,17 @@
module Unison.Styles where
import Color
import Color (Color)
import Easing (Easing)
import Easing
import Color exposing (Color)
import Elmz.Signal as Signals
import Elmz.Layout (Layout, Region)
import Elmz.Layout exposing (Layout, Region)
import Elmz.Layout as L
import Graphics.Input.Field as Field
import Graphics.Element (Element)
import Graphics.Element exposing (Element)
import Graphics.Element as E
import Graphics.Collage as C
import List
import List ((::))
import Signal
import Text (Style)
import Text exposing (Style)
import Text as T
import Time
@ -62,16 +59,16 @@ menuHeader =
, line = Nothing }
codeText : String -> Element
codeText s = T.leftAligned (T.style code (T.fromString s))
codeText s = E.leftAligned (T.style code (T.fromString s))
boldCodeText : String -> Element
boldCodeText s = T.leftAligned (T.style { code | bold <- True } (T.fromString s))
boldCodeText s = E.leftAligned (T.style { code | bold <- True } (T.fromString s))
centeredCodeText : String -> Element
centeredCodeText s = T.centered (T.style code (T.fromString s))
centeredCodeText s = E.centered (T.style code (T.fromString s))
menuHeaderText : String -> Element
menuHeaderText s = T.leftAligned (T.style menuHeader (T.fromString s))
menuHeaderText s = E.leftAligned (T.style menuHeader (T.fromString s))
menuSeparator : Int -> Element
menuSeparator width =
@ -111,10 +108,10 @@ currentSymbol : Element
currentSymbol = outline' okColor 6 16 16
numericLiteral : String -> Element
numericLiteral s = T.leftAligned (T.style { code | color <- belizeHole } (T.fromString s))
numericLiteral s = E.leftAligned (T.style { code | color <- belizeHole } (T.fromString s))
stringLiteral : String -> Element
stringLiteral s = T.leftAligned (T.style { code | color <- wisteria } (T.fromString s))
stringLiteral s = E.leftAligned (T.style { code | color <- wisteria } (T.fromString s))
cells : k -> Element -> List (Layout k) -> Layout k
cells k ifEmpty ls = let cs = List.map (\l -> L.fill bg (L.pad 5 0 l)) (L.row ls) in case cs of
@ -205,17 +202,6 @@ contain : Element -> Element
contain e =
E.container (E.widthOf e) (E.heightOf e) E.middle e
spinner : Signal Element
spinner =
let pct n = toFloat (n%60) / 60.0
t = Signal.map pct (Signals.count (Time.fps 60))
rect = E.color midnightBlue (E.spacer 5 10)
sep = E.spacer 1 1
render pct = E.flow E.right
[ rect, sep
, E.opacity (Easing.easeInOutExpo pct) rect ]
in Signal.map render t
blank : Element
blank = codeText "_"
@ -243,7 +229,3 @@ midnightBlue = Color.rgb 44 62 80
midnightBlueA alpha = Color.rgba 44 62 80 alpha
concrete = Color.rgb 149 165 166
asbestos = Color.rgb 127 140 141
main =
let scene e = E.flow E.down [ E.spacer 1 50, E.flow E.right [ E.spacer 50 1, e]]
in Signal.map scene spinner

View File

@ -1,9 +1,9 @@
module Unison.Symbol where
import Elmz.Json.Encoder as Encoder
import Elmz.Json.Encoder (Encoder)
import Elmz.Json.Encoder exposing (Encoder)
import Elmz.Json.Decoder as Decoder
import Elmz.Json.Decoder (Decoder)
import Elmz.Json.Decoder exposing (Decoder)
type Fixity = InfixL | InfixR | Infix | Prefix

View File

@ -1,33 +1,32 @@
module Unison.Term where
import Array
import Array (Array)
import Array exposing (Array)
import Debug
import Dict
import Dict (Dict)
import Dict exposing (Dict)
import Elmz.Distance as Distance
import Elmz.Maybe as EM
import Elmz.Layout (Layout)
import Elmz.Json.Encoder (Encoder)
import Elmz.Layout exposing (Layout)
import Elmz.Json.Encoder exposing (Encoder)
import Elmz.Json.Encoder as Encoder
import Elmz.Json.Decoder (Decoder)
import Elmz.Json.Decoder exposing (Decoder)
import Elmz.Json.Decoder as Decoder
import Elmz.Trie (Trie)
import Elmz.Trie exposing (Trie)
import Elmz.Trie as Trie
import List
import List ((::))
import Maybe
import Set
import Set (Set)
import Set exposing (Set)
import String
import Unison.Reference as R
import Unison.Hash (Hash)
import Unison.Hash exposing (Hash)
import Unison.Hash as H
import Unison.Metadata (Metadata)
import Unison.Symbol (Symbol,Fixity)
import Unison.Metadata exposing (Metadata)
import Unison.Symbol exposing (Symbol,Fixity)
import Unison.Symbol as Symbol
import Unison.Metadata as Metadata
import Unison.Path (..)
import Unison.Path exposing (..)
import Unison.Path as Path
import Unison.Type as T
type alias E = Path.E

View File

@ -1,17 +1,17 @@
module Unison.TermExplorer where
import Debug
import Dict (Dict)
import Dict exposing (Dict)
import Dict as Dict
import Elmz.Moore (Moore(..))
import Elmz.Moore exposing (Moore(..))
import Elmz.Moore as Moore
import Elmz.Layout as Layout
import Elmz.Layout (Layout)
import Elmz.Layout exposing (Layout)
import Elmz.Movement as Movement
import Elmz.Selection1D as Selection1D
import Elmz.Matcher as Matcher
import Graphics.Element as Element
import Graphics.Element (Element)
import Graphics.Element exposing (Element)
import Graphics.Input.Field as Field
import List
import Maybe
@ -19,18 +19,18 @@ import Result
import Signal
import String
import Unison.Metadata as Metadata
import Unison.Metadata (Metadata,Query)
import Unison.Metadata exposing (Metadata,Query)
import Unison.Node as Node
import Unison.Path as Path
import Unison.Path (Path)
import Unison.Path exposing (Path)
import Unison.Reference as Reference
import Unison.Reference (Reference)
import Unison.Reference exposing (Reference)
import Unison.SearchboxParser as SearchboxParser
import Unison.Styles as Styles
import Unison.Term as Term
import Unison.Term (Term)
import Unison.Term exposing (Term)
import Unison.Type as Type
import Unison.Type (Type)
import Unison.Type exposing (Type)
import Unison.View as View
type alias LocalFocus =

View File

@ -1,16 +1,16 @@
module Unison.Type where
import Elmz.Json.Decoder (Decoder)
import Elmz.Json.Decoder exposing (Decoder)
import Elmz.Json.Decoder as Decoder
import Elmz.Json.Encoder (Encoder)
import Elmz.Json.Encoder exposing (Encoder)
import Elmz.Json.Encoder as Encoder
import List
import String
import Unison.Metadata (Metadata)
import Unison.Metadata exposing (Metadata)
import Unison.Metadata as Metadata
import Unison.Reference (Reference)
import Unison.Reference exposing (Reference)
import Unison.Reference as Reference
import Unison.Symbol (Symbol)
import Unison.Symbol exposing (Symbol)
import Unison.Symbol as Symbol
type Literal

View File

@ -4,28 +4,27 @@ import Array
import Color
import Debug
import Elmz.Distance as Distance
import Elmz.Layout (Layout)
import Elmz.Layout exposing (Layout)
import Elmz.Layout as L
import Elmz.Moore (Moore(..))
import Elmz.Moore exposing (Moore(..))
import Elmz.Moore as Moore
import Elmz.Trie as Trie
import Elmz.Trie (Trie)
import Elmz.Trie exposing (Trie)
import List
import List ((::))
import Graphics.Element as E
import Maybe
import Unison.Reference as R
import Unison.Hash (Hash)
import Unison.Metadata (Metadata)
import Unison.Symbol (Fixity)
import Unison.Hash exposing (Hash)
import Unison.Metadata exposing (Metadata)
import Unison.Symbol exposing (Fixity)
import Unison.Symbol as Symbol
import Unison.Metadata as Metadata
import Unison.Styles (codeText)
import Unison.Styles exposing (codeText)
import Unison.Styles as Styles
import Unison.Term (..)
import Unison.Term exposing (..)
import Unison.Term as Term
import Unison.Type as Type
import Unison.Path (..)
import Unison.Path exposing (..)
import Unison.Path as Path
import String
import Text
@ -322,16 +321,16 @@ builtins env allowBreak availableWidth ambientPrec cur =
in Just (L.embed t (E.spacer w' h'))
App (Ref (R.Builtin "View.text")) style -> case e of
-- todo, actually interpret style
Lit (Text s) -> Just (L.embed t (Text.leftAligned (Text.style Text.defaultStyle (Text.fromString s))))
Lit (Text s) -> Just (L.embed t (E.leftAligned (Text.style Text.defaultStyle (Text.fromString s))))
App (App (App (Ref (R.Builtin "View.textbox")) (Ref (R.Builtin alignment))) (Lit (Term.Distance d))) style ->
case e of
Lit (Text s) ->
-- todo, actually interpret style
let f = case alignment of
"Text.left" -> Text.leftAligned
"Text.right" -> Text.rightAligned
"Text.center" -> Text.centered
"Text.justify" -> Text.justified
"Text.left" -> E.leftAligned
"Text.right" -> E.rightAligned
"Text.center" -> E.centered
"Text.justify" -> E.justified
e = f (Text.style Text.defaultStyle (Text.fromString s))
rem = availableWidth `max` floor (Distance.pixels d (toFloat availableWidth))
e' = if E.widthOf e > rem then E.width rem e else e