about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2023-09-10 21:45:59 -0700
committerKartik K. Agaram <vc@akkartik.com>2023-09-10 21:45:59 -0700
commit706296388809984b20b32edf3fa8f576c85508c5 (patch)
tree1f0038c4b646dd4c051e3b721024ea792d5e4783
parent790b7f18dbfb6c7dfcc72a872bc62e6075af6ae8 (diff)
downloadview.love-706296388809984b20b32edf3fa8f576c85508c5.tar.gz
Revert "deemphasize the source editor"
Now that we have decent error handling, I think we can encourage people
to press ctrl+e again.

This reverts commit 4b43e9e85d985bcedd105fa9693ae751e5b6d0b6.
-rw-r--r--README.md1
-rw-r--r--main.lua12
-rw-r--r--source.lua7
3 files changed, 3 insertions, 17 deletions
diff --git a/README.md b/README.md
index 0833aa6..291aed9 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,7 @@ While editing text:
 * `ctrl+=` to zoom in, `ctrl+-` to zoom out, `ctrl+0` to reset zoom
 * `alt+right`/`alt+left` to jump to the next/previous word, respectively
 * mouse drag or `shift` + movement to select text, `ctrl+a` to select all
+* `ctrl+e` to modify the sources
 
 For shortcuts while editing drawings, consult the online help. Either:
 * hover on a drawing and hit `ctrl+h`, or
diff --git a/main.lua b/main.lua
index c3b5a26..39c44a2 100644
--- a/main.lua
+++ b/main.lua
@@ -1,13 +1,5 @@
--- Wrapper that combines the app with a 'source editor' that allows editing
--- the app in place.
---
--- The source editor is a sharp tool. I find it convenient, but I also often
--- end up in a bad state that requires dropping down to external tools
--- (editor, file manager) to fix.
---
--- Downstream forks provide a better, "freewheeling" experience for editing
--- apps live. The source editor provides a half-baked experience for editing
--- some of the primitives used by true freewheeling apps.
+-- Entrypoint for the app. You can edit this file from within the app if
+-- you're careful.
 
 -- files that come with LÖVE; we can't edit those from within the app
 utf8 = require 'utf8'
diff --git a/source.lua b/source.lua
index b4e1078..d9e44b6 100644
--- a/source.lua
+++ b/source.lua
@@ -1,10 +1,3 @@
--- Source editor that lets me edit the app from within. However, it's a sharp
--- tool. I find it convenient, but I also often end up in a bad state that
--- requires dropping down to external tools (editor, file manager) to fix.
---
--- Downstream forks provide a better, "freewheeling" experience for editing
--- apps live. The source editor provides a half-baked experience for editing
--- some of the primitives used by true freewheeling apps.
 source = {}
 
 Editor_state = {}
ent.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
utf8 = require 'utf8'

require 'app'
require 'test'

require 'keychord'
require 'button'

require 'main_tests'

-- delegate most business logic to a layer that can be reused by other projects
require 'edit'
Editor_state = {}

-- called both in tests and real run
function App.initialize_globals()
  -- tests currently mostly clear their own state

  -- resize
  Last_resize_time = nil

  -- blinking cursor
  Cursor_time = 0
end

-- called only for real run
function App.initialize(arg)
  love.keyboard.setTextInput(true)  -- bring up keyboard on touch screen
  love.keyboard.setKeyRepeat(true)

  love.graphics.setBackgroundColor(1,1,1)

  if love.filesystem.getInfo('config') then
    load_settings()
  else
    initialize_default_settings()
  end

  if #arg > 0 then
    Editor_state.filename = arg[1]
    Editor_state.lines = load_from_disk(Editor_state.filename)
    Editor_state.screen_top1 = {line=1, pos=1}
    Editor_state.cursor1 = {line=1, pos=1}
    for i,line in ipairs(Editor_state.lines) do
      if line.mode == 'text' then
        Editor_state.cursor1.line = i
        break
      end
    end
  else
    Editor_state.lines = load_from_disk(Editor_state.filename)
    if Editor_state.cursor1.line > #Editor_state.lines or Editor_state.lines[Editor_state.cursor1.line].mode ~= 'text' then
      for i,line in ipairs(Editor_state.lines) do
        if line.mode == 'text' then
          Editor_state.cursor1.line = i
          break
        end
      end
    end
  end
  love.window.setTitle('lines.love - '..Editor_state.filename)

  if #arg > 1 then
    print('ignoring commandline args after '..arg[1])
  end

  if rawget(_G, 'jit') then
    jit.off()
    jit.flush()
  end
end

function load_settings()
  -- maximize window to determine maximum allowable dimensions
  love.window.setMode(0, 0)  -- maximize
  App.screen.width, App.screen.height, App.screen.flags = love.window.getMode()
  --
  local settings = json.decode(love.filesystem.read('config'))
  love.window.setPosition(settings.x, settings.y, settings.displayindex)
  App.screen.width, App.screen.height, App.screen.flags = love.window.getMode()
  App.screen.flags.resizable = true
  App.screen.flags.minwidth = math.min(App.screen.width, 200)
  App.screen.flags.minheight = math.min(App.screen.width, 200)
  App.screen.width, App.screen.height = settings.width, settings.height
  love.window.setMode(App.screen.width, App.screen.height, App.screen.flags)
  Editor_state = edit.initialize_state(Margin_top, Margin_left, App.screen.width-Margin_right)
  Editor_state.filename = settings.filename
  Editor_state.font_height = settings.font_height
  love.graphics.setFont(love.graphics.newFont(Editor_state.font_height))
  Editor_state.line_height = math.floor(Editor_state.font_height*1.3)
  Editor_state.em = App.newText(love.graphics.getFont(), 'm')
  Editor_state.screen_top1 = settings.screen_top
  Editor_state.cursor1 = settings.cursor
end

function initialize_default_settings()
  local font_height = 20
  love.graphics.setFont(love.graphics.newFont(font_height))
  local em = App.newText(love.graphics.getFont(), 'm')
  initialize_window_geometry(App.width(em))
  Editor_state = edit.initialize_state(Margin_top, Margin_left, App.screen.width-Margin_right)
  Editor_state.font_height = font_height
  Editor_state.line_height = math.floor(font_height*1.3)
  Editor_state.em = em
end

function initialize_window_geometry(em_width)
  -- maximize window
  love.window.setMode(0, 0)  -- maximize
  App.screen.width, App.screen.height, App.screen.flags = love.window.getMode()
  -- shrink height slightly to account for window decoration
  App.screen.height = App.screen.height-100
  App.screen.width = 40*em_width
  App.screen.flags.resizable = true
  App.screen.flags.minwidth = math.min(App.screen.width, 200)
  App.screen.flags.minheight = math.min(App.screen.width, 200)
  love.window.setMode(App.screen.width, App.screen.height, App.screen.flags)
end

function App.resize(w, h)
--?   print(("Window resized to width: %d and height: %d."):format(w, h))
  App.screen.width, App.screen.height = w, h
  Text.redraw_all(Editor_state)
  Editor_state.selection1 = {}  -- no support for shift drag while we're resizing
  Text.tweak_screen_top_and_cursor(Editor_state, Editor_state.left, Editor_state.right)
  Last_resize_time = App.getTime()
end

function App.filedropped(file)
  -- first make sure to save edits on any existing file
  if Editor_state.next_save then
    save_to_disk(Editor_state.lines, Editor_state.filename)
  end
  -- clear the slate for the new file
  App.initialize_globals()  -- in particular, forget all undo history
  Editor_state.filename = file:getFilename()
  file:open('r')
  Editor_state.lines = load_from_file(file)
  file:close()
  for i,line in ipairs(Editor_state.lines) do
    if line.mode == 'text' then
      Editor_state.cursor1.line = i
      break
    end
  end
  love.window.setTitle('Text with Editor_state.lines - '..Editor_state.filename)
end

function App.draw()
  Button_handlers = {}
  edit.draw(Editor_state)
end

function App.update(dt)
  Cursor_time = Cursor_time + dt
  -- some hysteresis while resizing
  if Last_resize_time then
    if App.getTime() - Last_resize_time < 0.1 then
      return
    else
      Last_resize_time = nil
    end
  end
  edit.update(Editor_state, dt)
end

function love.quit()
  edit.quit(Editor_state)
  -- save some important settings
  local x,y,displayindex = love.window.getPosition()
  local filename = Editor_state.filename
  if filename:sub(1,1) ~= '/' then
    filename = love.filesystem.getWorkingDirectory()..'/'..filename  -- '/' should work even on Windows
  end
  local settings = {
    x=x, y=y, displayindex=displayindex,
    width=App.screen.width, height=App.screen.height,
    font_height=Editor_state.font_height,
    filename=filename,
    screen_top=Editor_state.screen_top1, cursor=Editor_state.cursor1}
  love.filesystem.write('config', json.encode(settings))
end

function App.mousepressed(x,y, mouse_button)
  Cursor_time = 0  -- ensure cursor is visible immediately after it moves
  return edit.mouse_pressed(Editor_state, x,y, mouse_button)
end

function App.mousereleased(x,y, mouse_button)
  Cursor_time = 0  -- ensure cursor is visible immediately after it moves
  return edit.mouse_released(Editor_state, x,y, mouse_button)
end

function App.textinput(t)
  Cursor_time = 0  -- ensure cursor is visible immediately after it moves
  return edit.textinput(Editor_state, t)
end

function App.keychord_pressed(chord, key)
  Cursor_time = 0  -- ensure cursor is visible immediately after it moves
  return edit.keychord_pressed(Editor_state, chord, key)
end

function App.keyreleased(key, scancode)
  Cursor_time = 0  -- ensure cursor is visible immediately after it moves
  return edit.key_released(Editor_state, key, scancode)
end