Skip to content

Commit

Permalink
cell copying
Browse files Browse the repository at this point in the history
  • Loading branch information
bcpeinhardt committed Nov 2, 2024
1 parent 664f39d commit 13c1648
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 45 deletions.
7 changes: 7 additions & 0 deletions squared_away/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@

<title>🚧 form</title>

<style>
input.errorcell {
outline: 1px solid maroon;
border: 1px solid maroon;
}
</style>

<!-- Uncomment this if you add the TailwindCSS integration -->
<!-- <link rel="stylesheet" href="/priv/static/form.css"> -->
<script type="module" src="/priv/static/squared_away.mjs"></script>
Expand Down
139 changes: 99 additions & 40 deletions squared_away/src/squared_away.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import squared_away_lang as lang
import squared_away_lang/error
import squared_away_lang/grid
import squared_away_lang/interpreter/value
import squared_away_lang/typechecker/typ
import squared_away_lang/typechecker/type_error

const initial_grid_width = 5

Expand All @@ -36,9 +34,11 @@ fn focus(id: String) -> Nil
/// To start, our model will be a 5x5 grid of Strings
type Model {
Model(
holding_shift: Bool,
grid_width: Int,
grid_height: Int,
display_mode: DisplayMode,
display_coords: Bool,
active_cell: Option(grid.GridKey),
src_grid: grid.Grid(String),
value_grid: grid.Grid(Result(value.Value, error.CompileError)),
Expand All @@ -49,7 +49,6 @@ type Model {
type DisplayMode {
DisplayValues
DisplayFormulas
DisplayGridCoords
}

fn init(_flags) -> #(Model, effect.Effect(Msg)) {
Expand All @@ -59,9 +58,11 @@ fn init(_flags) -> #(Model, effect.Effect(Msg)) {

let model =
Model(
holding_shift: False,
grid_width: initial_grid_width,
grid_height: initial_grid_height,
display_mode: DisplayValues,
display_coords: False,
active_cell: None,
src_grid:,
value_grid:,
Expand All @@ -75,10 +76,12 @@ fn init(_flags) -> #(Model, effect.Effect(Msg)) {
type Msg {
Noop
UserToggledDisplayMode(to: DisplayMode)
UserToggledDisplayCoords(to: Bool)
UserSetCellValue(key: grid.GridKey, val: String)
UserFocusedOnCell(key: grid.GridKey)
UserFocusedOffCell
UserHitKeyInCell(key: grid.GridKey, keyboard_key: String)
UserReleasedKeyInCell(keyboard_key: String)
}

fn update_grid(model: Model) -> Model {
Expand Down Expand Up @@ -110,30 +113,79 @@ fn update(model: Model, msg: Msg) -> #(Model, effect.Effect(Msg)) {
UserToggledDisplayMode(display_mode) -> {
#(Model(..model, display_mode:), effect.none())
}
UserToggledDisplayCoords(display_coords) -> {
#(Model(..model, display_coords:), effect.none())
}
UserFocusedOnCell(key) -> {
#(Model(..model, active_cell: Some(key)), effect.none())
}
UserFocusedOffCell -> {
#(Model(..model, active_cell: None), effect.none())
}
UserHitKeyInCell(key, keyboard_key) -> {
case keyboard_key {
"Enter" -> {
let new_active_cell = grid.cell_underneath(model.src_grid, key)
case new_active_cell {
Error(_) -> #(Model(..model, active_cell: None), effect.none())
Ok(new) -> {
focus(grid.to_string(new))
#(Model(..model, active_cell: Some(new)), effect.none())
case keyboard_key, model.holding_shift {
"Shift", False -> #(Model(..model, holding_shift: True), effect.none())
"ArrowUp", _ ->
set_active_cell_to(model, grid.cell_above(model.src_grid, key))
"ArrowLeft", _ ->
set_active_cell_to(model, grid.cell_to_the_left(model.src_grid, key))
"Enter", _ | "ArrowDown", False ->
set_active_cell_to(model, grid.cell_underneath(model.src_grid, key))
"ArrowRight", False ->
set_active_cell_to(model, grid.cell_to_the_right(model.src_grid, key))
"ArrowRight", True -> {
let formula = grid.get(model.src_grid, key)
let maybe_cell_to_right = grid.cell_to_the_right(model.src_grid, key)
case maybe_cell_to_right {
Error(Nil) -> #(model, effect.none())
Ok(cell_to_right) -> {
let src_grid = grid.insert(model.src_grid, cell_to_right, formula)
let id = grid.to_string(cell_to_right)
focus(id)
let new_model =
Model(..model, src_grid:, active_cell: Some(cell_to_right))
#(update_grid(new_model), effect.none())
}
}
}
"ArrowDown", True -> {
let formula = grid.get(model.src_grid, key)
let maybe_cell_below = grid.cell_underneath(model.src_grid, key)
case maybe_cell_below {
Error(Nil) -> #(model, effect.none())
Ok(cell_below) -> {
let src_grid = grid.insert(model.src_grid, cell_below, formula)
let id = grid.to_string(cell_below)
focus(id)
let new_model =
Model(..model, src_grid:, active_cell: Some(cell_below))
#(update_grid(new_model), effect.none())
}
}
}
_, _ -> #(model, effect.none())
}
}
UserReleasedKeyInCell(keyboard_key) -> {
case keyboard_key {
"Shift" -> #(Model(..model, holding_shift: False), effect.none())
_ -> #(model, effect.none())
}
}
}
}

fn set_active_cell_to(model, key: Result(grid.GridKey, Nil)) {
case key {
Error(_) -> #(model, effect.none())
Ok(key) -> {
let id = grid.to_string(key)
focus(id)
#(Model(..model, active_cell: Some(key)), effect.none())
}
}
}

fn view(model: Model) -> element.Element(Msg) {
let error_to_display =
list.find_map(model.errors_to_display, fn(e) {
Expand All @@ -150,44 +202,52 @@ fn view(model: Model) -> element.Element(Msg) {
|> dict.map_values(fn(_, keys) {
let cells =
list.map(keys, fn(key) {
let on_enter = event.on_keydown(UserHitKeyInCell(key, _))
let on_keydown = event.on_keydown(UserHitKeyInCell(key, _))
let on_keyup = event.on_keyup(UserReleasedKeyInCell)
let on_input = event.on_input(UserSetCellValue(key:, val: _))
let out_of_focus = event.on_blur(UserFocusedOffCell)
let on_focus = event.on_focus(UserFocusedOnCell(key))
let id = attribute.id(grid.to_string(key))
let value = case model.display_mode {
DisplayFormulas -> grid.get(model.src_grid, key)
DisplayGridCoords -> string.inspect(key)
DisplayValues -> case model.active_cell == Some(key) {
False -> case grid.get(model.value_grid, key) {
let value =
case model.display_mode, model.active_cell == Some(key) {
DisplayFormulas, _ | DisplayValues, True ->
grid.get(model.src_grid, key)
DisplayValues, _ ->
case grid.get(model.value_grid, key) {
Error(e) -> error.error_type_string(e)
Ok(v) -> value.value_to_string(v)
}
True -> grid.get(model.src_grid, key)
}
} |> attribute.value
|> attribute.value

let styles = case
list.find(model.errors_to_display, fn(i) { i.0 == key })
{
Error(Nil) -> []
Ok(_) -> [attribute.style([#("background-color", "red")])]
let cell_is_errored =
list.any(model.errors_to_display, fn(i) { i.0 == key })
let error_class = case cell_is_errored {
False -> attribute.none()
True -> attribute.class("errorcell")
}

let input = html.input([
on_input,
on_focus,
out_of_focus,
value,
on_enter,
id
])
let input =
html.input([
on_input,
on_focus,
out_of_focus,
value,
on_keydown,
on_keyup,
id,
attribute.type_("text"),
error_class,
])

html.td(styles, {
[
input
]
})
case model.display_coords {
False -> html.td([], [input])
True ->
html.td([], [
html.label([], t(grid.to_string(key) <> ": ")),
input,
])
}
})

html.tr([], cells)
Expand All @@ -214,10 +274,9 @@ fn view(model: Model) -> element.Element(Msg) {

let grid_mode_toggle =
html.input([
attribute.type_("radio"),
attribute.name("display_mode"),
attribute.type_("checkbox"),
attribute.id("grid_mode"),
event.on_check(fn(_) { UserToggledDisplayMode(DisplayGridCoords) }),
event.on_check(UserToggledDisplayCoords),
])

let grid_mode_toggle_label =
Expand Down
7 changes: 6 additions & 1 deletion squared_away/src/squared_away_ffi.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
export function focus(id) {
document.getElementById(id).focus()
const input = document.getElementById(id);
input.focus();
const length = input.value.length;
setTimeout(() => {
input.setSelectionRange(length, length);
}, 0);
}
15 changes: 11 additions & 4 deletions squared_away_lang/src/squared_away_lang/grid.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
//// boilerplate around results for get operations, so I'm gonna try and extract
//// them to a module

import gleam/int
import gleam/dict
import gleam/int
import gleam/list
import gleam/result

// Making the type generic since we do a grid of src
// and a grid of interpreted values
Expand All @@ -18,8 +17,8 @@ pub opaque type GridKey {
}

pub fn to_string(key: GridKey) -> String {
let GridKey(row, col) = key
int.to_string(row) <> "_" <> int.to_string(col)
let GridKey(row, col) = key
"(" <> int.to_string(row) <> "," <> int.to_string(col) <> ")"
}

pub fn row(grid_key: GridKey) -> Int {
Expand Down Expand Up @@ -80,6 +79,14 @@ pub fn cell_underneath(grid: Grid(a), key: GridKey) -> Result(GridKey, Nil) {
list.find(grid.cells, fn(k) { k.row == key.row + 1 && k.col == key.col })
}

pub fn cell_above(grid: Grid(a), key: GridKey) -> Result(GridKey, Nil) {
list.find(grid.cells, fn(k) { k.row + 1 == key.row && k.col == key.col })
}

pub fn cell_to_the_left(grid: Grid(a), key: GridKey) -> Result(GridKey, Nil) {
list.find(grid.cells, fn(k) { k.row == key.row && k.col + 1 == key.col })
}

pub fn intersect(row_cell: GridKey, col_cell: GridKey) -> Result(GridKey, Nil) {
let GridKey(row, col_check) = row_cell
let GridKey(row_check, col) = col_cell
Expand Down

0 comments on commit 13c1648

Please sign in to comment.