I am using this Ace Editor adapted to 
Elm: https://github.com/DenisKolodin/elm-ace

However, my problem seems not specific to that editor, but applies to any 
program that wants to support an embedded editor whose contents can be 
updated by the program, and also that can respond to global keypress events.

The editor text can be updated either by

1) the user typing, or
2) the program updating the text (e.g., pressing a "load default text" 
button)

The user can also press some keyboard shortcuts (',' and '.') to do other 
actions. These are handled by my update function:

update msg model = 
    ...
    KeyMsg keyCode ->
        if keyCode == Char.toCode ',' then
            update Backward model
        else if keyCode == Char.toCode '.' then
            update Forward model
        else
            ( model, Cmd.none )

This is called whenever the user presses any key because of this 
subscription that uses the elm-lang/keyboard library:

subscriptions model =
    Keyboard.presses KeyMsg

The problem is that all of the keypresses made when editing cause the 
update function to be called, not just the two that I care about. Most of 
them are not ',' or '.' so the model is returned unchanged in the else 
clause above.

But this causes the following problem: in my view function, the editor 
updates its contents to be whatever the model says the text should be (for 
instance, the user may press a button that loads some default text):

view model = 
    ...
    Ace.toHtml
        [ Ace.value model.text        -- updates editor to display model.
text
        , Ace.onSourceChange NewText  -- updates model.text to be latest 
editor contents
        ]
        []

The purpose of onSourceChange above is to trigger another call to the update 
function, which allows me to update my model text with the new editor 
contents. In other words, the two lines above are the bi-directional data 
binding between model.text and the editor's text contents. The second one 
implies a call to the update function:

update msg model = 
    ...
    NewText newText ->
        ( {model | text = newText}, Cmd.none )

The problem is that the Elm runtime is ordering events so that the text in 
the editor never gets updated when the user tries to type new text. 

Here is the order of events:

   1. User types to edit text in the editor.
   2. Because of the subscription I registered for global keystroke events, 
   Elm runtime calls update with the message KeyMsg indicating which key 
   was pressed.
   3. Model is updated (in the KeyMsg case of my update function) to the 
   "new" model, but most of the time this is identical to the old model since 
   only ',' and '.' actually return a changed model. Importantly, this is 
   the *old* text, not containing the new character that the user typed.
   4. The view function is called, and the Ace.toHtml updates the text 
   contents of the editor to be what the model.text field is... which erases 
   in the editor the new character that the user just tried to enter, since 
   model.text still has the old, pre-keystroke text.
   5. The update function is called with a NewText message, but it's too 
   late. By now the editor has had its new text erased and replaced with the 
   old text. Ideally, this event would have happened in between steps 1 and 2, 
   but steps 2,3,4 seem to happen before this does.

I'm not sure how to get around this. 

*Idea 1:* figure out a way to prevent the update function from being called 
at all when a keystroke other than ',' or '.' occurs. This is not ideal 
because then they can't type ',' or '.' in the editor, but it would be a 
workaround because I could perhaps assign Ctrl+... keys or something.

*Idea 2:* Re-order the updates so that, when the user enters new text in 
the editor, it is guaranteed that update is called with the NewText message 
before it is called with the KeyMsg message. I don't know of any way to do 
this.

*Idea 3:* Re-design how I'm passing messages through the system so that, no 
matter the order in which messages are delivered, if the user tries to 
enter new text, eventually that new text makes its way into the model.

*Idea 4:* don't use the Keyboard library to respond to global keypress 
events, and find something that is more specific to what I want (to give 
the user a couple of keyboard shortcuts, without calling the update 
function every time any key is pressed). Suggestions for such a library?

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to