Emacs can slow down when opening files with exceptionally long lines, such as minified JavaScript or CSS, SQL dumps, or large JSON files. One solution to prevent these files from slowing down Emacs is to use the built-in global-so-long-mode (or so-long-mode). When you visit such files, this mode detects abnormally long lines and automatically disables expensive minor modes that could slow down or, in the worst cases, freeze Emacs.
Below is a configuration to improve how global-so-long-mode handles these files, balancing performance and usability.
Why so-long is still relevant
Emacs 29 introduced native optimizations, such as long-line-threshold and large-hscroll-threshold, for handling files with long lines. However, so-long-mode is still relevant because Emacs does not automatically disable built-in and third-party minor modes. In a modern configuration, so-long-minor-mode functions as a safety switch to disable resource intensive modes on a per-buffer basis.
Managing syntax highlighting
By default, so-long disables font-lock-mode entirely to maximize performance. The configuration below retains syntax highlighting but limits the decoration level:
(with-eval-after-load 'so-long
(setq so-long-minor-modes (delq 'font-lock-mode so-long-minor-modes))
(add-to-list 'so-long-variable-overrides '(treesit-font-lock-level . 1))
(add-to-list 'so-long-variable-overrides '(font-lock-maximum-decoration . 1)))
The benefit is that you maintain basic syntax highlighting, which makes code easier to read than plain text. The tradeoff is that even minimal font-lock parsing consumes CPU cycles, which can still cause minor performance degradation in massive files.
Changing the default action
By default, when so-long detects a file with abnormally long lines, its standard behavior is to replace the buffer's major mode with so-long-mode. This is undesirable if you want to edit files using their original major mode, which allows you to retain useful minor-mode behavior and tooling.
Setting so-long-action to so-long-minor-mode retains the original major mode while applying the configured so-long performance mitigations:
(setq so-long-action 'so-long-minor-mode)
Note: The trade-off is that so-long-minor-mode leaves some features active that so-long-mode would otherwise disable. If additional performance-heavy features cause latency, you must disable them explicitly by appending them to so-long-minor-modes (see below).
Extending target modes
By default, so-long primarily targets prog-mode, css-mode, sgml-mode, nxml-mode, and fundamental-mode, leaving other buffers unprotected.
Adding conf-mode and text-mode to so-long-target-modes extends this protection to structured configurations, documentation, and patch files:
(with-eval-after-load 'so-long
(add-to-list 'so-long-target-modes 'text-mode)
(add-to-list 'so-long-target-modes 'conf-mode))
In practice, generated configuration files (such as dense JSON or exported INI data), single-line log dumps treated as text, and massive diffs regularly contain long lines that can slow down the Emacs.
Managing variable overrides and display behavior
When so-long triggers, it overrides buffer-local variables to improve performance. However, some default settings degrade usability by marking buffers as read-only and allowing save-place-mode to reposition the point within long lines.
The snippet below adjusts so-long-variable-overrides to keep the buffer writable and disables save-place-alist, preventing unnecessary cursor calculations on long lines:
(with-eval-after-load 'so-long
(add-to-list 'so-long-variable-overrides '(save-place-alist . nil))
(setf (alist-get 'buffer-read-only so-long-variable-overrides nil t) nil))
Respecting line truncation and visual line movement
By default, to improve performance with long lines, so-long-mode does the following:
- Disables
truncate-lines to force soft line wrapping. This limits the display to as few logical lines as possible, reducing the rendering load for massive lines.
- Enables
line-move-visual, so that movement commands navigate by small visual lines rather than leaping across potentially thousands of characters between logical lines.
While these defaults prevent layout calculation lag on massive files, they change standard movement and display behavior. Since Emacs 29 introduced display engine optimizations for long lines, these workarounds are less strictly necessary. If you prefer so-long to respect your global preferences, you can prevent it from overriding them.
Here is how to prevent so-long from modifying them:
(with-eval-after-load 'so-long
(setf (alist-get 'truncate-lines so-long-variable-overrides nil t) nil)
(setf (alist-get 'line-move-visual so-long-variable-overrides nil t) nil))
Note: Adding the above ensures your truncate-lines and line-move-visual preferences are preserved. However, scrolling might be slower as a result.
Keeping basic UI elements
The default so-long-minor-modes includes display-line-numbers-mode. The following configuration removes it so it remains active when so-long triggers:
(with-eval-after-load 'so-long
(setq so-long-minor-modes (delq 'display-line-numbers-mode so-long-minor-modes)))
Disabling resource-intensive minor modes
Many third-party packages can become expensive on buffers containing very long lines. This block adds commonly used minor modes to so-long-minor-modes. When so-long triggers, active modes in this list are disabled for the current buffer.
(with-eval-after-load 'so-long
(dolist (mode '(;; Structural Editing and Parenthesis Matching
paredit-mode
enhanced-evil-paredit-mode
rainbow-delimiters-mode
smartparens-mode
smartparens-strict-mode
;; Regex and Custom Highlighting
easy-escape-minor-mode
highlight-defined-mode
highlight-indent-guides-mode
auto-composition-mode
;; Outline Scanning / Text folding
outline-minor-mode
treesit-fold-mode
ts-fold-mode
ts-fold-indicators-mode
;; State & History Persistence / I/O
undo-fu-session-mode
undo-tree-mode
better-jumper-local-mode
auto-revert-mode
;; Formatters & Whitespace Managers
aggressive-indent-mode
stripspace-local-mode
ws-butler-mode
;; Linters & Language Servers
eglot--managed-mode
eldoc-mode
flycheck-mode
flymake-mode
;; Spell Checkers
jinx-mode
spell-fu-mode
;; UI Overlays & Margins
indent-bars-mode
highlight-numbers-mode
diff-hl-mode
git-gutter-mode
line-reminder-mode
page-break-lines-mode
hl-fill-column-mode))
(add-to-list 'so-long-minor-modes mode)))
Adjusting the threshold
You can control when so-long activates by adjusting the following threshold:
(setq so-long-threshold 6000)
Enable the mode globally
Finally, enable global-so-long-mode by adding the following to your Emacs configuration:
(global-so-long-mode 1)