immerrr / lua-mode

Emacs major mode for editing Lua
http://immerrr.github.io/lua-mode
GNU General Public License v3.0
314 stars 74 forks source link

Very slow performance when inserting newlines #178

Closed mtreca closed 3 years ago

mtreca commented 3 years ago

I noticed that inserting newlines on a moderately sized lua file (~250 lines) causes my Emacs to freeze for a couple seconds. I haven't changed any default values from lua mode, nor do I use company mode or any other editing package.

Inserting around 20 newlines (by keeping the return key pressed) generates the following profiler-report log:

- command-execute                                                4029  79%
 - call-interactively                                            4028  79%
  - funcall-interactively                                        4028  79%
   - newline                                                     3793  74%
    - self-insert-command                                        3792  74%
     - electric-indent-post-self-insert-function                 3791  74%
      - indent-according-to-mode                                 3791  74%
       - lua-indent-line                                         3791  74%
        - lua-calculate-indentation                              3790  74%
         - lua-calculate-indentation-block-modifier               3785  74%
          - lua-calculate-indentation-info                       3785  74%
           - lua-is-continuing-statement-p                       3554  69%
            - lua-is-continuing-statement-p-1                    3476  68%
             - lua--backward-up-list-noerror                     3430  67%
              - lua-backward-up-list                             3429  67%
               - lua-find-matching-token-word                    2906  57%
                - lua-find-matching-token-word                   1821  35%
                 - lua-find-matching-token-word                  1110  21%
                  - lua-find-regexp                               695  13%
                   - lua-comment-or-string-p                      662  13%
                    - syntax-ppss                                 653  12%
                       #<compiled 0x30bb641>                        1   0%
                  - lua-find-matching-token-word                  388   7%
                   - lua-find-regexp                              325   6%
                    - lua-comment-or-string-p                     303   5%
                       syntax-ppss                                295   5%
                   - lua-find-matching-token-word                  52   1%
                    - lua-find-regexp                              50   0%
                     - lua-comment-or-string-p                     49   0%
                        syntax-ppss                                48   0%
                     lua-get-block-token-info                       1   0%
                    lua-get-block-token-info                        1   0%
                 - lua-find-regexp                                685  13%
                  - lua-comment-or-string-p                       655  12%
                     syntax-ppss                                  637  12%
                   lua-get-block-token-info                         4   0%
                - lua-find-regexp                                1045  20%
                 - lua-comment-or-string-p                        963  18%
                  - syntax-ppss                                   932  18%
                     #<compiled 0x30e6bc9>                          1   0%
                  lua-get-block-token-info                         12   0%
               - lua-find-regexp                                  500   9%
                - lua-comment-or-string-p                         436   8%
                   syntax-ppss                                    419   8%
                 lua-get-block-token-info                           3   0%
             - lua-forward-line-skip-blanks                        35   0%
              - lua-comment-or-string-p                            30   0%
                 syntax-ppss                                       30   0%
               lua-last-token-continues-p                           4   0%
               lua-first-token-continues-p                          3   0%
            - lua--backward-up-list-noerror                        52   1%
             - lua-backward-up-list                                52   1%
              - lua-find-regexp                                    46   0%
               - lua-comment-or-string-p                           42   0%
                  syntax-ppss                                      41   0%
              - lua-find-matching-token-word                        6   0%
               - lua-find-regexp                                    6   0%
                - lua-comment-or-string-p                           6   0%
                   syntax-ppss                                      5   0%
            - lua--goto-line-beginning-rightmost-closer                 23   0%
             - lua-comment-or-string-p                             20   0%
                syntax-ppss                                        19   0%
               back-to-indentation                                  1   0%
           - lua-calculate-indentation-info-1                     230   4%
            - lua-make-indentation-info-pair                      226   4%
             - lua-calculate-indentation-info                     177   3%
              - lua-is-continuing-statement-p                     176   3%
               - lua-is-continuing-statement-p-1                  176   3%
                - lua--backward-up-list-noerror                   172   3%
                 - lua-backward-up-list                           172   3%
                  - lua-find-matching-token-word                  136   2%
                   - lua-find-matching-token-word                 104   2%
                    - lua-find-matching-token-word                 67   1%
                     - lua-find-regexp                             38   0%
                      - lua-comment-or-string-p                    35   0%
                         syntax-ppss                               35   0%
                     - lua-find-matching-token-word                 25   0%
                      - lua-find-regexp                            19   0%
                       - lua-comment-or-string-p                   18   0%
                          syntax-ppss                              18   0%
                      - lua-find-matching-token-word                  2   0%
                       - lua-find-regexp                            2   0%
                        + lua-comment-or-string-p                   2   0%
                        lua-get-block-token-info                    1   0%
                       lua-get-block-token-info                     1   0%
                    - lua-find-regexp                              35   0%
                     - lua-comment-or-string-p                     34   0%
                        syntax-ppss                                31   0%
                      lua-get-block-token-info                      1   0%
                   - lua-find-regexp                               26   0%
                    - lua-comment-or-string-p                      22   0%
                       syntax-ppss                                 20   0%
                  - lua-find-regexp                                32   0%
                   - lua-comment-or-string-p                       30   0%
                      syntax-ppss                                  30   0%
                    lua-get-block-token-info                        2   0%
                - lua-forward-line-skip-blanks                      4   0%
                 - lua-comment-or-string-p                          4   0%
                    syntax-ppss                                     4   0%
             - lua-goto-matching-block-token                       48   0%
              - lua-find-matching-token-word                       48   0%
               - lua-find-regexp                                   34   0%
                - lua-comment-or-string-p                          33   0%
                   syntax-ppss                                     32   0%
               - lua-find-matching-token-word                      14   0%
                - lua-find-regexp                                  13   0%
                 - lua-comment-or-string-p                         13   0%
                    syntax-ppss                                    13   0%
            - lua-find-regexp                                       4   0%
             - lua-comment-or-string-p                              4   0%
                syntax-ppss                                         4   0%
         - lua-forward-line-skip-blanks                             3   0%
          - lua-comment-or-string-p                                 3   0%
             syntax-ppss                                            2   0%
         - lua-calculate-indentation-override                       2   0%
          - lua--goto-line-beginning-rightmost-closer                  2   0%
           - lua-comment-or-string-p                                2   0%
              syntax-ppss                                           2   0%
        - lua-comment-or-string-p                                   1   0%
           syntax-ppss                                              1   0%
     - #<compiled 0x31253b5>                                        1   0%
      - move-to-left-margin                                         1   0%
       - current-left-margin                                        1   0%
        - back-to-indentation                                       1   0%
         - backward-prefix-chars                                    1   0%
          - internal--syntax-propertize                             1   0%
             syntax-propertize                                      1   0%
      add-hook                                                      1   0%
   + counsel-M-x                                                  235   4%
+ ...                                                            1033  20%
+ redisplay_internal (C function)                                  13   0%
+ timer-event-handler                                               4   0%
  whitespace-post-command-hook                                      1   0%
  sp--post-command-hook-handler                                     1   0%

I can provide the associated file (it is a AwesomeWM configuration file) if needed.

immerrr commented 3 years ago

Hi,

This definitely does not look healthy. It would be really helpful if you could provide the exact file that exhibits this behaviour.

Thanks!

mtreca commented 3 years ago

Thanks for your reply. In the meantime I tested the file using emacs -Q and by only loading lua-mode. The problem is still there. I also know the file has no errors (load properly in Awesome and luacheck does not report any errors).

Here is the file:

local beautiful = require("beautiful")
local menubar = require("menubar")
local gears = require("gears")

local grid = dofile("/home/mtreca/etc/dotfiles/awesome/grid.lua")
local widget = dofile("/home/mtreca/etc/dotfiles/awesome/widget.lua")
local prgm = dofile("/home/mtreca/etc/dotfiles/awesome/prgm.lua")

beautiful.init("/home/mtreca/etc/dotfiles/awesome/theme.lua")

gears.wallpaper.set("#dddddd")

local naughty = require("naughty")

naughty.config.padding = beautiful.useless_gap
naughty.config.spacing = beautiful.useless_gap
naughty.config.defaults.timeout = 120

local awful = require("awful")
local wibox = require("wibox")

dat = widget.box({x = 1842, width = 70})
dat:setup {
   layout = wibox.layout.fixed.horizontal,
   wibox.widget.textclock(" %H:%M")
}

bar = widget.box({x = 180, width = 150})

widget.set(bar, { widget.msg("prv"), widget.msg("wrk"), widget.bat(), wibox.widget.separator({ forced_width = 10, thickness = 0 })})

widget.sound_bar_init()
widget.brightness_bar_init()

awful.screen.connect_for_each_screen(
   function(s)

      -- Tags
      s.tag = widget.box({width = 170})
      awful.tag({ "I", "II", "III", "IV", "V" }, s, awful.layout.layouts[1])
      widget.set(s.tag, awful.widget.taglist(s, awful.widget.taglist.filter.all))

      -- Command Prompt
      s.cmd = awful.widget.prompt { done_callback = function() s.run.visible = false end }
      s.run = widget.box({x = 860, width = 200, visible = false, ontop = true})
      widget.set(s.run, s.cmd)

   end
)

local function get_term()
   local cmd = "emacsclient -c -n " ..
      "--frame-parameters='(quote (name . \"emacsterm\"))' " ..
      "-e '(vterm)' " ..
      "-e '(set-face-attribute (quote header-line) (selected-frame) :background \"white\" :height 50)' " ..
      "-e '(setq header-line-format \"\")' " ..
      "-e '(hide-mode-line-mode)'"
   awful.spawn(cmd)
end

local function get_emacs()
   local cmd = "emacsclient -c -n"
   awful.spawn(cmd)
end

local function echo_cmd(cmd, prefix)
   -- TODO Customize prefix here
   local out = function(line) naughty.notify({ text = prefix .. line }) end
   -- TODO Change notification to error here
   local err = function(line) naughty.notify({ text = "ERR:"..line }) end
   awful.spawn.with_line_callback(cmd, { stdout = out, stderr = err,})
end

local function togglemenu()
   local s = awful.screen.focused()
   s.run.visible = true
   s.cmd:run()
end

local function togglefullscreen(c)
   c.fullscreen = not c.fullscreen
   c:raise()
end

require("awful.autofocus")

modkey = "Mod4"

globalkeys = gears.table.join(
    awful.key({ modkey, },         "p", awful.tag.viewprev),
    awful.key({ modkey, },         "n", awful.tag.viewnext),
    awful.key({ modkey, },         "Tab", function () awful.client.focus.byidx(1) end),
    awful.key({ modkey, "Shift" }, "Tab", function () awful.client.focus.byidx(-1) end),
    awful.key({ modkey, },         "t", function () awful.spawn("urxvt") end),
    awful.key({ modkey, },         "Return", prgm.trm),
    awful.key({ modkey, },         "e", get_emacs),
    awful.key({ modkey, "Shift" }, "r", awesome.restart),
    awful.key({ modkey, "Shift" }, "d", awesome.quit),
    awful.key({ modkey, }, "x", function () togglemenu() end),
    awful.key({ modkey, }, "c", naughty.destroy_all_notifications),
    awful.key({ }, "XF86AudioRaiseVolume", widget.volume_up),
    awful.key({ }, "XF86AudioLowerVolume", widget.volume_down),
    awful.key({ }, "XF86AudioMute", widget.volume_toggle),
    awful.key({ }, "XF86MonBrightnessDown", widget.brightness_down),
    awful.key({ }, "XF86MonBrightnessUp", widget.brightness_up)
)

clientkeys = gears.table.join(
    awful.key({modkey}, "f",     function (c) togglefullscreen(c) end),
    awful.key({modkey}, "g",     function (c) grid.init(c, {2, 2, 5, 5, 9, 9}) end),
    awful.key({modkey}, "m",     function (c) grid.init(c, {0, 0, 9, 9, 9, 9}) end),
    awful.key({modkey}, "Left",  function (c) grid.move(c, -1, 0) end),
    awful.key({modkey}, "Down",  function (c) grid.move(c, 0, 1) end),
    awful.key({modkey}, "Up",    function (c) grid.move(c, 0, -1) end),
    awful.key({modkey}, "Right", function (c) grid.move(c, 1, 0) end),
    awful.key({modkey, "Shift"}, "Left", function (c) grid.resize(c, -1, 0) end),
    awful.key({modkey, "Shift"}, "Down", function (c) grid.resize(c, 0, 1) end),
    awful.key({modkey, "Shift"}, "Up", function (c) grid.resize(c, 0, -1) end),
    awful.key({modkey, "Shift"}, "Right", function (c) grid.resize(c, 1, 0) end),
    awful.key({modkey}, "d", function (c) c:kill() end)
)

for i = 1, 5 do
    globalkeys = gears.table.join(globalkeys,
        awful.key({ modkey }, "#" .. i + 9,
                  function ()
                        local screen = awful.screen.focused()
                        local tag = screen.tags[i]
                        if tag then
                           tag:view_only()
                        end
                  end,
                  {description = "view tag #"..i, group = "tag"}),
        awful.key({ modkey, "Shift" }, "#" .. i + 9,
                  function ()
                      if client.focus then
                          local tag = client.focus.screen.tags[i]
                          if tag then
                              client.focus:move_to_tag(tag)
                          end
                     end
                  end,
                  {description = "move focused client to tag #"..i, group = "tag"})
    )
end

clientbuttons = gears.table.join(
    awful.button({ }, 1, function (c)
        c:emit_signal("request::activate", "mouse_click", {raise = true})
    end),
    awful.button({ modkey }, 1, function (c)
        c:emit_signal("request::activate", "mouse_click", {raise = true})
        awful.mouse.client.move(c)
    end),
    awful.button({ modkey }, 3, function (c)
        c:emit_signal("request::activate", "mouse_click", {raise = true})
        awful.mouse.client.resize(c)
    end)
)

root.keys(globalkeys)

awful.rules.rules = {
    { rule = { },
      properties = { border_width = beautiful.border_width,
                     border_color = beautiful.border_normal,
                     focus = awful.client.focus.filter,
                     titlebar_enabled = false,
                     raise = true,
                     size_hints_honor = false,
                     keys = clientkeys,
                     buttons = clientbuttons,
                     screen = awful.screen.preferred,
                     placement = awful.placement.no_overlap+awful.placement.no_offscreen,
                     }},

    { rule_any = { name = {"emacs"} },
      properties = {size_hints_honor = false},
      callback = function (c)
         grid.init(c, {1, 1, 7, 7, 9, 9})
      end
    },

    { rule_any = { name = {"emacsterm"} },
      properties = {size_hints_honor = false},
      callback = function (c)
         grid.init(c, {3, 3, 3, 3, 9, 9})
      end
    },

    { rule_any = { class = {"Firefox"} },
      properties = {size_hints_honor = false},
      callback = function (c)
         grid.init(c, {1, 1, 7, 7, 9, 9})
      end
    }

}

client.connect_signal("focus",   function(c) c.border_color = beautiful.border_focus end)
client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)

if awesome.startup_errors then
    naughty.notify({ preset = naughty.config.presets.critical,
                     title = "AwesomeWM Configuration Error!",
                     text = awesome.startup_errors })
end

do
    local in_error = false
    awesome.connect_signal("debug::error", function (err)
        if in_error then return end
        in_error = true
        naughty.notify({ preset = naughty.config.presets.critical,
                         title = "AwesomeWM Configuration Error",
                         text = tostring(err) })
        in_error = false
    end)
end
immerrr commented 3 years ago

I have finished a bunch of changes that should make lua-mode snappier and merged them to master. Please, give it a spin and let me know if it helps.

mtreca commented 3 years ago

Wow, that is a lot of commits!

I tested the new lua mode version on the same file, and performance is indeed much better. No stuttering when mashing newlines.

Thanks a lot!

ralessi commented 3 years ago

I am experiencing the exact same issue with a 2133-line lua file. Since this issue is solved, should I split my file into smaller pieces?

Thank you.