<commit_before>module Unison.TermExplorer where

import Debug
import Dict (Dict)
import Dict as Dict
import Elmz.Moore (Moore(..))
import Elmz.Moore as Moore
import Elmz.Layout as Layout
import Elmz.Layout (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.Input.Field as Field
import List
import Maybe
import Result
import Signal
import String
import Unison.Metadata as Metadata
import Unison.Metadata (Metadata,Query)
import Unison.Node as Node
import Unison.Path as Path
import Unison.Path (Path)
import Unison.Reference as Reference
import Unison.Reference (Reference)
import Unison.SearchboxParser as SearchboxParser
import Unison.Styles as Styles
import Unison.Term as Term
import Unison.Term (Term)
import Unison.Type as Type
import Unison.Type (Type)
import Unison.View as View

type alias LocalFocus =
  { rootTerm : Term
  , pathToClosedSubterm : Path
  , closedSubterm : Term
  , pathFromClosedSubterm : Path }

path : LocalFocus -> Path
path focus = focus.pathToClosedSubterm ++ focus.pathFromClosedSubterm

type Event
  = Open View.Env LocalFocus Field.Content
  | Navigate (Selection1D.Event Term)
  | Click (Int,Int)
  | SearchResults Node.SearchResults
  | LocalInfoResults Node.LocalInfo
  | FieldContent Field.Content
  | Env View.Env

type alias Model =
  Moore Event { selection : Maybe (LocalFocus, Term)
              , view : Element
              , request : Maybe Request }

type Request
  = LocalInfo LocalFocus
  | Search (Term, Path, Int, Metadata.Query, Maybe Type)

type alias Completions =
  { literals : List (String,Element,Maybe Term)
  , locals : List (String,Element,Maybe Term)
  , searchResults : Matcher.Model (String,Element,Maybe Term) }

allCompletions : Completions -> List (String,Element,Maybe Term)
allCompletions c = c.literals ++ c.locals ++ ((Moore.extract c.searchResults).matches)

model : (Field.Content -> Signal.Message) -> Model
model searchbox =
  let
    closed e = case e of
      Open env focus content -> Just <|
        let f = viewField searchbox False content Nothing
        in Moore { selection = Nothing, request = Just (LocalInfo focus), view = f } (initialize env focus content)
      _ -> Nothing

    initialize env focus content e = case e of
      LocalInfoResults info -> Just <|
        let req = Search ( focus.closedSubterm
                         , focus.pathFromClosedSubterm
                         , 7
                         , content.string
                         , Just info.admissible )
            sel = Selection1D.model
            la cur n = (String.padLeft (n+1) '.' "", showAppBlanks env (path focus) n, Just (appBlanks n cur))
            currentApps = case Term.at focus.pathFromClosedSubterm focus.closedSubterm of
              Nothing -> []
              Just cur -> List.map (la cur) info.localApplications
            completions =
              { locals = currentApps ++ List.map (searchEntry True env (path focus)) info.wellTypedLocals
              , literals = parseSearchbox info.admissible content.string
              , searchResults = Matcher.model match }
            infoLayout' = infoLayout env (path focus) info
            (sel, layout') = layout env.metadata
                                     (path focus)
                                     searchbox
                                     (allCompletions completions)
                                     Selection1D.model
                                     content
                                     infoLayout'
            vw = Layout.element layout'
        in Moore { selection = Nothing, request = Just req, view = vw }
                 (search env.metadata focus completions sel content infoLayout' layout')
      _ -> Nothing

    search metadata focus completions sel content infoLayout layout' e = case e of
      SearchResults results -> Just <|
        let
          completions' = processSearchResults results completions content.string
          dict = Dict.fromList results.references
          metadata' r = case Dict.get (Reference.toKey r) dict of
            Nothing -> metadata r
            Just md -> md
          keyedCompletions = Moore.extract completions'.searchResults |> .matches
          (sel', layout'') = layout metadata' (path focus) searchbox keyedCompletions sel content infoLayout
        in Moore { selection = Nothing, request = Nothing, view = Layout.element layout'' } <|
           search metadata' focus completions' sel' content infoLayout layout''
      Navigate nav -> Moore.step sel nav `Maybe.andThen` \sel -> Just <|
        let (sel'', layout'') = layout metadata (path focus) searchbox (allCompletions completions) sel content infoLayout
        in Moore { selection = Nothing, request = Nothing, view = Layout.element layout'' } <|
           search metadata focus completions sel'' content infoLayout layout''
      _ -> Nothing

    match s (k,_,_) = String.startsWith (String.toLower k) (String.toLower s)

  in Moore { selection = Nothing, request = Nothing, view = Element.empty } closed

processSearchResults : Node.SearchResults -> Completions -> String -> Completions
processSearchResults results cs query =
  Debug.crash "todo"

parseSearchbox : Type -> String -> List (String, Element, Maybe Term)
parseSearchbox admissible s =
  case SearchboxParser.parseTerm s of
    Result.Err _   -> [(s, Styles.codeText s, Nothing )]
    Result.Ok term -> case View.literalKey term of
      Just k ->
        let edit = if Term.checkLiteral term admissible then Just term else Nothing<commit_msg>Filled in rest of explorer state machine<commit_after>module Unison.TermExplorer where

import Debug
import Dict (Dict)
import Dict as Dict
import Elmz.Moore (Moore(..))
import Elmz.Moore as Moore
import Elmz.Layout as Layout
import Elmz.Layout (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.Input.Field as Field
import List
import Maybe
import Result
import Signal
import String
import Unison.Metadata as Metadata
import Unison.Metadata (Metadata,Query)
import Unison.Node as Node
import Unison.Path as Path
import Unison.Path (Path)
import Unison.Reference as Reference
import Unison.Reference (Reference)
import Unison.SearchboxParser as SearchboxParser
import Unison.Styles as Styles
import Unison.Term as Term
import Unison.Term (Term)
import Unison.Type as Type
import Unison.Type (Type)
import Unison.View as View

type alias LocalFocus =
  { rootTerm : Term
  , pathToClosedSubterm : Path
  , closedSubterm : Term
  , pathFromClosedSubterm : Path }

path : LocalFocus -> Path
path focus = focus.pathToClosedSubterm ++ focus.pathFromClosedSubterm

type Event
  = Open View.Env LocalFocus Field.Content
  | Navigate (Selection1D.Event Term)
  | Accept
  | Click (Int,Int)
  | SearchResults Node.SearchResults
  | LocalInfoResults Node.LocalInfo
  | FieldContent Field.Content

type alias Model =
  Moore Event { selection : Maybe (LocalFocus, Term)
              , view : Element
              , request : Maybe Request }

type Request
  = LocalInfo LocalFocus
  | Search (Term, Path, Int, Metadata.Query, Maybe Type)

type alias Completions =
  { literals : List (String,Element,Maybe Term)
  , locals : List (String,Element,Maybe Term)
  , results : Matcher.Model (String,Element,Maybe Term) }

allCompletions : Completions -> List (String,Element,Maybe Term)
allCompletions c =
  c.results `Moore.feed` (Matcher.Query { string = "", values = c.literals ++ c.locals })
  |> Moore.extract |> .matches

model : (Field.Content -> Signal.Message) -> Model
model searchbox =
  let
    closed e = case e of
      Open env focus content -> Just <|
        let f = viewField searchbox False content Nothing
        in Moore { selection = Nothing, request = Just (LocalInfo focus), view = f } (initialize env focus content)
      _ -> Nothing

    initialize env focus content e = case e of
      LocalInfoResults info -> Just <|
        let req = Search ( focus.closedSubterm
                         , focus.pathFromClosedSubterm
                         , 7
                         , content.string
                         , Just info.admissible )
            sel = Selection1D.model
            la cur n = (String.padLeft (n+1) '.' "", showAppBlanks env (path focus) n, Just (appBlanks n cur))
            currentApps = case Term.at focus.pathFromClosedSubterm focus.closedSubterm of
              Nothing -> []
              Just cur -> List.map (la cur) info.localApplications
            completions =
              { locals = currentApps ++ List.map (searchEntry True env (path focus)) info.wellTypedLocals
              , literals = parseSearchbox info.admissible content.string
              , results = Matcher.model match }
            infoLayout' = infoLayout env (path focus) info
            (sel, layout') = layout env.metadata
                                     (path focus)
                                     searchbox
                                     (allCompletions completions)
                                     Selection1D.model
                                     content
                                     infoLayout'
            vw = Layout.element layout'
        in Moore { selection = Nothing, request = Just req, view = vw }
                 (search info.admissible env.metadata focus completions sel content infoLayout' layout')
      _ -> Nothing

    search admissible metadata focus completions sel content infoLayout layout' e = case e of
      SearchResults results -> Just <|
        let
          completions' = processSearchResults results completions content.string
          dict = Dict.fromList results.references
          metadata' r = case Dict.get (Reference.toKey r) dict of
            Nothing -> metadata r
            Just md -> md
          matches = Moore.extract completions'.results |> .matches
          (sel', layout'') = layout metadata' (path focus) searchbox matches sel content infoLayout
        in Moore { selection = Nothing, request = Nothing, view = Layout.element layout'' } <|
           search admissible metadata' focus completions' sel' content infoLayout layout''
      Navigate nav -> Moore.step sel nav `Maybe.andThen` \sel -> Just <|
        let (sel'', layout'') = layout metadata (path focus) searchbox (allCompletions completions) sel content infoLayout
        in Moore { selection = Nothing, request = Nothing, view = Layout.element layout'' } <|
           search admissible metadata focus completions sel'' content infoLayout layout''
      Accept ->
        let valids = validCompletions (.matches << Moore.extract <| completions.results)
        in Maybe.withDefault (Just state0) ( (Moore.extract sel |> snd) `Maybe.andThen`
            \i -> Selection1D.index i valids `Maybe.andThen`
            \(_,term) -> (Just << Just) (
              Moore { selection = Just (focus, term), request = Nothing, view = Element.empty }
              closed
           ))
      Click xy ->
        case search admissible metadata focus completions sel content infoLayout layout' (Navigate (Selection1D.Mouse xy)) of
          Nothing -> search admissible metadata focus completions sel content infoLayout layout' Accept
          Just m -> Moore.step m Accept
      FieldContent content -> Just <|
        let
          q = Matcher.Query { string = content.string, values = completions.literals ++ completions.locals }
          results = Moore.feed completions.results q
          matches = Moore.extract results |> .matches
          completions' = { completions | results <- results }
          (sel', layout'') = layout metadata (path focus) searchbox matches sel content infoLayout
          req = Maybe.map mkquery (Moore.extract results |> .query)
          mkquery q = Search ( focus.closedSubterm
                             , focus.pathFromClosedSubterm
                             , 7
                             , q
                             , Just admissible )
        in
          Moore { selection = Nothing, request = req, view = Layout.element layout'' }
          (search admissible metadata focus completions' sel' content infoLayout layout'')
      _ -> Nothing

    match s (k,_,_) = String.startsWith (String.toLower k) (String.toLower s)
    state0 = Moore { selection = Nothing, request = Nothing, view = Element.empty } closed
  in state0

processSearchResults : Node.SearchResults -> Completions -> String -> Completions
processSearchResults results cs query =
  Debug.crash "todo"

parseSearchbox : Type -> String -> List (String, Element, Maybe Term)
parseSearchbox admissible s =
  case SearchboxParser.parseTerm s of
    Result.Err _   -> [(s, Styles.codeText s, Nothing )]
    Result.Ok term -> case View.literalKey term of
      Just k ->
        let edit = if Term.checkLiteral term admissible then Just term else Nothing
{'fraction_non_alphanumeric': 0.07917304747320061, 'fraction_numerical': 0.0015313935681470138, 'mean_word_length': 2.4416337285902503, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5376104', 'n_tokens_mistral': 3404, 'n_tokens_neox': 3322, 'n_words': 1183}