Skip to content

Commit

Permalink
Support autocomplete (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
albertprz committed Apr 6, 2024
1 parent bb89b8a commit 6aac88d
Show file tree
Hide file tree
Showing 28 changed files with 561 additions and 310 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,26 @@ for use for enterprise, personal & educational purposes.

- [:heavy_check_mark:] Provide a no frills, minimalistic GUI supporting all basic spreadsheet functionality regarding navigation, cell management, formula evaluation & automatic cell updates.

- [:heavy_check_mark:] Expose a high level pure functional dynamic formula language interpreted at the browser, with expresiveness similar to the term level language in Haskell or Purescript, albeit with familiar syntax and idioms to popular spreadhsheet applications and mainstream languages.
- [:heavy_check_mark:] Expose a high level pure functional dynamic formula language interpreted at the browser, with expresiveness similar to the term level language in Haskell or Purescript, albeit with familiar syntax and idioms to popular spreadsheet applications and mainstream languages.

- [:heavy_check_mark:] Expose a prelude library with commonly used functions and combinators, loaded at startup.

- [:heavy_check_mark:] Support formula edition with syntax highlighting and function signatures for the current function at the cursor.

- Include Opt-in automatic formatting for formulas when evaluated.

- Support auto completion for imported and module aliased global functions.
- [:heavy_check_mark:] Support auto completion for imported and module aliased top-level functions and operators.

- Expose a view to query (possibly in a Hoogle / Pursuit fashion), view, update and upload new global functions & operators on a per module basis. This view would surface the same editing capatibilities as the formula box in the main spreadsheet view.

- Expose customization options for navigation, keybindings, spreadsheet behaviour as well as display and themes configuration.
- Include Opt-in automatic formatting for formulas when evaluated.

- Enable the use of formulas for filtering & sorting rows.

- Support authenticated persistence & retrieval from a catalog of private spreadsheets via a future backend.
- Expose customization options for navigation, keybindings, spreadsheet behaviour as well as display and themes configuration.

- Support Import & Export of spreadsheets from and to Excel and Google Sheets with the proper mapping of cell values & formulas.

- Support authenticated persistence & retrieval from a catalog of private spreadsheets via a future backend.


## Screenshots

Expand Down
1 change: 1 addition & 0 deletions dev/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8">
<title>Puresheet</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
</head>
<body>
<script src="./index.js" type="module"></script>
Expand Down
2 changes: 1 addition & 1 deletion src/CSS/CSSPrelude.purs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module CSSPrelude

import Tecton hiding (ElementId(..))

import App.CSS.ClassNames (aboveSelection, atLeftSelection, atRightSelection, belowSelection, cellSyntax, columnHeader, copySelection, cornerHeader, formulaBox, formulaCellInput, formulaContainer, inSelection, invalidFormula, keywordSyntax, mainContainer, numberSyntax, operatorSyntax, regularSyntax, rowHeader, selectedCellInput, selectedHeader, selectedSheetCell, sheet, sheetCell, stringSyntax, strippedSheet, symbolSyntax, unknownFormula, validFormula) as ClassNames
import App.CSS.ClassNames (aboveSelection, atLeftSelection, atRightSelection, belowSelection, cellSyntax, columnHeader, copySelection, cornerHeader, formulaBox, formulaCellInput, formulaSectionContainer, inSelection, invalidFormula, keywordSyntax, mainContainer, numberSyntax, operatorSyntax, regularSyntax, rowHeader, selectedCellInput, selectedHeader, selectedSheetCell, sheet, sheetCell, stringSyntax, strippedSheet, symbolSyntax, unknownFormula, validFormula) as ClassNames
import App.CSS.Common (black, blue, brown, darkGrey, green, grey, grey2, hex, lightGreen, lightGrey, lighterGreen, lighterGrey, lighterRed, lighterYellow, mustard, orange, pink, purple, red, white, yellow) as Common
import App.CSS.Ids (ElementId(..), cellId, formulaBoxId, formulaCellInputId, inputElement, selectedCellInputId) as Ids
import Data.Tuple (Tuple) as Tuple
Expand Down
17 changes: 13 additions & 4 deletions src/CSS/ClassNames.purs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ cornerHeader = ClassName "corner-header"
mainContainer :: ClassName
mainContainer = ClassName "main-container"

formulaContainer :: ClassName
formulaContainer = ClassName "formula-container"
formulaSectionContainer :: ClassName
formulaSectionContainer = ClassName "formula-container"

formulaBoxContainer :: ClassName
formulaBoxContainer = ClassName "formula-box-container"
Expand All @@ -71,8 +71,14 @@ selectedCellInput = ClassName "selected-cell-input"
formulaCellInput :: ClassName
formulaCellInput = ClassName "formula-cell-input"

formulaSignature :: ClassName
formulaSignature = ClassName "formula-signature"
functionSignature :: ClassName
functionSignature = ClassName "function-signature"

suggestionsDropdown :: ClassName
suggestionsDropdown = ClassName "suggestions-dropdown"

suggestionOption :: ClassName
suggestionOption = ClassName "suggestion-option"

cellSyntax :: ClassName
cellSyntax = ClassName "cell-syntax"
Expand All @@ -97,3 +103,6 @@ functionSyntax = ClassName "function-syntax"

regularSyntax :: ClassName
regularSyntax = ClassName "regular-syntax"

materialIcons :: ClassName
materialIcons = ClassName "material-icons"
10 changes: 10 additions & 0 deletions src/CSS/Common.purs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ import FatPrelude

import Color (Color, fromHexString)
import Color as Color
import Tecton.Internal (Length, Measure, px)

formulaFontSize :: Measure Length
formulaFontSize = px 21

suggestionsFontSize :: Measure Length
suggestionsFontSize = px 22

signatureFontSize :: Measure Length
signatureFontSize = px 24

hex :: String -> Color
hex = fromMaybe black <<< fromHexString
Expand Down
7 changes: 5 additions & 2 deletions src/CSS/Ids.purs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ selectedCellInputId = ElementId "selected-cell-input"
formulaCellInputId :: ElementId
formulaCellInputId = ElementId "formula-cell-input"

formulaSignatureId :: ElementId
formulaSignatureId = ElementId "formula-signature"
functionSignatureId :: ElementId
functionSignatureId = ElementId "function-signature"

suggestionsDropdownId :: ElementId
suggestionsDropdownId = ElementId "suggestions-dropdown"

inputElement :: ElementType
inputElement = ElementType "input"
Expand Down
38 changes: 26 additions & 12 deletions src/CSS/Table.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ module App.CSS.Table where

import CSSPrelude

import App.CSS.ClassNames (formulaBoxContainer, formulaSignature, functionSyntax)
import App.CSS.Common (darkGreen, darkPink)
import App.CSS.ClassNames (formulaBoxContainer, functionSignature, functionSyntax, suggestionOption, suggestionsDropdown)
import App.CSS.Common (darkGreen, darkPink, formulaFontSize, signatureFontSize, suggestionsFontSize)
import Tecton.Internal (Length, Measure)
import Tecton.Rule as Rule
import Type.Prelude (Proxy)
Expand All @@ -12,7 +12,7 @@ css :: CSS
css = do

mainContainerCss
formulaContainerCss
formulaSectionContainerCss
formulaCss
selectedCellInputCss
formulaCellInputCss
Expand All @@ -26,10 +26,10 @@ mainContainerCss = do
backgroundColor := white
display := inlineTable

formulaContainerCss :: CSS
formulaContainerCss = do
formulaSectionContainerCss :: CSS
formulaSectionContainerCss = do

div &. formulaContainer ? Rule.do
div &. formulaSectionContainer ? Rule.do
display := flex
flexDirection := row
alignItems := center
Expand All @@ -53,17 +53,32 @@ formulaCss = do
borderStyle := solid
borderColor := grey2
borderWidth := px 3
fontSize := px 21
fontSize := formulaFontSize
fontWeight := bold
whiteSpace := breakSpaces
overflow := auto

universal &. formulaSignature ? Rule.do
universal &. suggestionsDropdown ? Rule.do
position := fixed
width := rem 16
backgroundColor := white

universal &. suggestionOption ? Rule.do
display := flex
padding := px 4 ~ px 0
alignContent := center
cursor := pointer
borderWidth := px 1
borderStyle := solid
borderColor := grey2
fontSize := suggestionsFontSize

universal &. functionSignature ? Rule.do
height := px 20
margin := px 20
marginTop := px 10
padding := px 0 ~ px 50
fontSize := px 24
fontSize := signatureFontSize
fontWeight := bold
textAlign := center

Expand Down Expand Up @@ -125,7 +140,7 @@ cellInputCommonCss = do
padding := px 15
borderColor := green
borderWidth := px 3
fontSize := px 21
fontSize := formulaFontSize
textAlign := center
outlineStyle := solid
outlineColor := green
Expand Down Expand Up @@ -212,11 +227,10 @@ cellCss = do
position := sticky
top := px 0
left := px 0
zIndex := 10
zIndex := 1
backgroundColor := lightGrey

th &. columnHeader ? Rule.do
position := sticky
top := px 0

th &. rowHeader ? Rule.do
Expand Down
27 changes: 16 additions & 11 deletions src/Components/Table/Handler.purs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import App.Components.Table.HandlerHelpers (cellArrowMove, cellMove, copyCells,
import App.Components.Table.Models (Action(..), AppState, EventTransition(..))
import App.Components.Table.Selection (MultiSelection(..), SelectionState(..))
import App.Evaluator.Formula (mkLocalContext)
import App.Utils.Dom (KeyCode(..), actOnElementById, ctrlKey, displayFunctionType, emptyFormulaBox, emptyFormulaSignature, focusById, focusCell, focusCellElem, introduceFormulaNewLine, isModifierKeyCode, performSyntaxHighlight, prevent, shiftKey, toEvent, toMouseEvent, updateFormulaBox, withPrevent)
import App.Utils.Dom (actOnElementById, displayFnSig, displayFnSuggestions, emptyFnSig, emptyFnSuggestions, emptyFormulaBox, focusById, focusCell, focusCellElem, insertFormulaNewLine, performSyntaxHighlight, prevent, updateFormulaBox, withPrevent)
import App.Utils.Event (ctrlKey, shiftKey, toEvent, toMouseEvent)
import App.Utils.HashMap (lookup2) as HashMap
import App.Utils.KeyCode (KeyCode(..), isModifierKeyCode)
import App.Utils.Selection (getSelection)
import App.Utils.Selection as Selection
import Data.HashMap (insert) as HashMap
Expand Down Expand Up @@ -38,9 +40,9 @@ handleAction Initialize = do

handleAction ResizeWindow = do
{ selectedCell } <- get
void $ selectCell $ OtherCell { column: mkColumn 'A', row: mkRow 1000 }
void $ selectCell $ OtherCell { column: mkColumn 'A', row: mkRow 1 }
void $ selectCell $ OtherCell selectedCell
selectCell $ OtherCell { column: mkColumn 'A', row: mkRow 1000 }
selectCell $ OtherCell { column: mkColumn 'A', row: mkRow 1 }
selectCell $ OtherCell selectedCell
liftEffect $ scroll 0 0 =<< window

handleAction (WriteSelectedCellInput cell) =
Expand Down Expand Up @@ -72,7 +74,7 @@ handleAction (FormulaKeyDown Enter ev)
| ctrlKey ev = withPrevent ev insertFormula

handleAction (FormulaKeyDown Enter ev) =
withPrevent ev (introduceFormulaNewLine *> performSyntaxHighlight)
withPrevent ev (insertFormulaNewLine *> performSyntaxHighlight)

handleAction (FormulaKeyDown Tab ev) =
withPrevent ev $ focusCell =<< gets _.selectedCell
Expand All @@ -84,7 +86,7 @@ handleAction (FormulaKeyDown _ _) =
modify_ _ { formulaState = UnknownFormula }

handleAction (FormulaKeyUp keyCode _) =
unless (isModifierKeyCode keyCode)
unless (isModifierKeyCode keyCode) do
performSyntaxHighlight

handleAction (FocusInFormula ev) = do
Expand Down Expand Up @@ -114,7 +116,8 @@ handleAction (DoubleClickCell cell ev) = withPrevent ev do

handleAction (FocusInCell cell _) = do
formulaText <- _.formulaText <$$> lookupFormula cell
emptyFormulaSignature
emptyFnSig
emptyFnSuggestions
case formulaText of
Just x -> updateFormulaBox x
Nothing -> emptyFormulaBox
Expand Down Expand Up @@ -185,10 +188,10 @@ handleAction (KeyDown (CharKeyCode 'G') ev)
handleAction (KeyDown _ _) =
pure unit

handleAction (KeyRelease Control ev) = withPrevent ev $
handleAction (KeyUp Control ev) = withPrevent ev $
modify_ _ { selectionState = NotStartedSelection }

handleAction (KeyRelease _ _) =
handleAction (KeyUp _ _) =
pure unit

handleAction (WheelScroll ev)
Expand Down Expand Up @@ -295,5 +298,7 @@ handleAction (DragHeader Over _ ev) =
handleAction (DragHeader _ _ _) =
pure unit

handleAction SelectionChange =
displayFunctionType <<< mkLocalContext =<< get
handleAction SelectionChange = do
ctx <- mkLocalContext <$> get
displayFnSig ctx
displayFnSuggestions ctx
3 changes: 2 additions & 1 deletion src/Components/Table/HandlerHelpers.purs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import App.Components.Table.Models (Action(..), AppState)
import App.Components.Table.Selection (MultiSelection(..), SelectionState(..), computeNextSelection, deserializeSelectionValues, getCellFromMove, getTargetCells, serializeSelectionValues)
import App.Interpreter.Formula (runFormula)
import App.Interpreter.Module (reloadModule)
import App.Utils.Dom (class IsEvent, emptyFormulaBox, focusCell, getClipboard, getFormulaBoxContents, getVisibleCols, getVisibleRows, parseElements, scrollCellLeft, scrollCellRight, shiftKey, withPrevent)
import App.Utils.Dom (emptyFormulaBox, focusCell, getClipboard, getFormulaBoxContents, getVisibleCols, getVisibleRows, parseElements, scrollCellLeft, scrollCellRight, withPrevent)
import App.Utils.Event (class IsEvent, shiftKey)
import App.Utils.HashMap (bulkDelete, lookup2, updateJust) as HashMap
import Bookhound.Parser (runParser)
import Data.Array as Array
Expand Down
4 changes: 2 additions & 2 deletions src/Components/Table/Models.purs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import App.Components.Table.Formula (Formula, FormulaId, FormulaState)
import App.Components.Table.Selection (MultiSelection, SelectionState)
import App.SyntaxTree.Common (Module, QVar, QVarOp)
import App.SyntaxTree.FnDef (FnInfo, OpInfo)
import App.Utils.Dom (KeyCode)
import App.Utils.KeyCode (KeyCode)
import Web.HTML.Event.DragEvent (DragEvent)
import Web.UIEvent.FocusEvent (FocusEvent)
import Web.UIEvent.KeyboardEvent (KeyboardEvent)
Expand Down Expand Up @@ -45,7 +45,7 @@ data Action
| DoubleClickCell Cell MouseEvent
| FocusInCell Cell FocusEvent
| KeyDown KeyCode KeyboardEvent
| KeyRelease KeyCode KeyboardEvent
| KeyUp KeyCode KeyboardEvent
| FormulaKeyDown KeyCode KeyboardEvent
| FormulaKeyUp KeyCode KeyboardEvent
| SelectedCellInputKeyDown KeyCode KeyboardEvent
Expand Down
19 changes: 12 additions & 7 deletions src/Components/Table/Renderer.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ module App.Components.Table.Renderer where
import FatPrelude hiding (div)
import Prim hiding (Row)

import App.CSS.ClassNames (aboveSelection, atLeftSelection, atRightSelection, belowSelection, columnHeader, copySelection, cornerHeader, formulaBox, formulaBoxContainer, formulaCellInput, formulaContainer, formulaSignature, inSelection, mainContainer, rowHeader, selectedCellInput, selectedHeader, selectedSheetCell, sheetCell)
import App.CSS.Ids (cellId, formulaBoxId, formulaCellInputId, formulaSignatureId, selectedCellInputId)
import App.CSS.ClassNames (aboveSelection, atLeftSelection, atRightSelection, belowSelection, columnHeader, copySelection, cornerHeader, formulaBox, formulaBoxContainer, formulaCellInput, formulaSectionContainer, functionSignature, inSelection, mainContainer, rowHeader, selectedCellInput, selectedHeader, selectedSheetCell, sheetCell, suggestionsDropdown)
import App.CSS.Ids (cellId, formulaBoxId, formulaCellInputId, functionSignatureId, selectedCellInputId, suggestionsDropdownId)
import App.Components.Table.Cell (Cell, CellValue, Column, Header(..), Row, allColumns, cellParser, parseCellValue, showCell)
import App.Components.Table.Formula (formulaStateToClass)
import App.Components.Table.Models (Action(..), AppState, EventTransition(..))
import App.Components.Table.Selection (SelectionState(..), isCellAboveSelection, isCellAtLeftSelection, isCellAtRightSelection, isCellBelowSelection, isCellInSelection, isColumnSelected, isRowSelected)
import App.Utils.Dom (mkKeyAction)
import App.Utils.KeyCode (mkKeyAction)
import Bookhound.Parser (runParser)
import Data.Array as Array
import Data.HashMap as HashMap
Expand All @@ -27,7 +27,7 @@ render
, selectionState
} =
div [ class_ mainContainer ]
[ div [ class_ formulaContainer ]
[ div [ class_ formulaSectionContainer ]
[ input
[ id $ show selectedCellInputId
, classes [ selectedCellInput ]
Expand All @@ -46,10 +46,15 @@ render
]
[]
, div
[ id $ show formulaSignatureId
, classes [ formulaSignature ]
[ id $ show functionSignatureId
, classes [ functionSignature ]
]
[ text mempty ]
, div
[ id $ show suggestionsDropdownId
, class_ suggestionsDropdown
]
[]
]
, input
[ id $ show formulaCellInputId
Expand All @@ -65,7 +70,7 @@ render
[ copySelection ]
, style "border-spacing: 0"
, onKeyDown $ mkKeyAction KeyDown
, onKeyUp $ mkKeyAction KeyRelease
, onKeyUp $ mkKeyAction KeyUp
, onWheel WheelScroll
]
[ renderHeader st
Expand Down
Loading

0 comments on commit 6aac88d

Please sign in to comment.