Here's a patch which allows me to use Emacs even for large single line JSON file without slowing it down. The idea is to limit Emacs search for new line to MAX_NEWLINE_DISTANCE. With fundamental mode and word-wrap on, I'm able to browse the file via page scroll, beginning/ end of line, beginning/ end of buffer and parenthesis matching. Only the up-down cursor movement is jarring.
Warning: It might or might not work for other scenarios.
diff --git a/src/insdel.c b/src/insdel.c
index 21acf0e61d..164c78fbda 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -36,6 +36,7 @@
static void insert_from_buffer_1 (struct buffer *, ptrdiff_t, ptrdiff_t, bool);
static void gap_left (ptrdiff_t, ptrdiff_t, bool);
static void gap_right (ptrdiff_t, ptrdiff_t);
+/* const int MAX_NEWLINE_DISTANCE = 256; */
/* List of elements of the form (BEG-UNCHANGED END-UNCHANGED CHANGE-AMOUNT)
describing changes which happened while combine_after_change_calls
@@ -2053,7 +2054,7 @@ invalidate_buffer_caches (struct buffer *buf, ptrdiff_t start, ptrdiff_t end)
set_buffer_internal (buf);
- line_beg = find_newline_no_quit (start, start_byte, -1,
+ line_beg = find_before_next_newline (start, start - 256, -1,
&start_byte);
set_buffer_internal (old);
}
diff --git a/src/search.c b/src/search.c
index 7389fbef0e..631f657b19 100644
--- a/src/search.c
+++ b/src/search.c
@@ -653,7 +653,7 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
struct region_cache *newline_cache;
struct buffer *cache_buffer;
- if (!end)
+ if (end <= 0)
{
if (count > 0)
end = ZV, end_byte = ZV_BYTE;
diff --git a/src/xdisp.c b/src/xdisp.c
index cbdef7ad11..eeebb74321 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -427,6 +427,8 @@ #define IT_DISPLAYING_WHITESPACE(it) \
&& (*BYTE_POS_ADDR (IT_BYTEPOS (*it)) == ' ' \
|| *BYTE_POS_ADDR (IT_BYTEPOS (*it)) == '\t'))))
+const int MAX_NEWLINE_DISTANCE = 256;
+
/* If all the conditions needed to print the fill column indicator are
met, return the (nonnegative) column number, else return a negative
value. */
@@ -6575,7 +6577,7 @@ back_to_previous_line_start (struct it *it)
ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
DEC_BOTH (cp, bp);
- IT_CHARPOS (*it) = find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it));
+ IT_CHARPOS (*it) = find_before_next_newline (cp, cp - MAX_NEWLINE_DISTANCE, -1, &IT_BYTEPOS (*it));
}
@@ -6607,7 +6609,6 @@ forward_to_next_line_start (struct it *it, bool *skipped_p,
ptrdiff_t old_selective;
bool newline_found_p = false;
int n;
- const int MAX_NEWLINE_DISTANCE = 500;
/* If already on a newline, just consume it to avoid unintended
skipping over invisible text below. */
@@ -6647,63 +6648,7 @@ forward_to_next_line_start (struct it *it, bool *skipped_p,
short-cut. */
if (!newline_found_p)
{
- ptrdiff_t bytepos, start = IT_CHARPOS (*it);
- ptrdiff_t limit = find_newline_no_quit (start, IT_BYTEPOS (*it),
- 1, &bytepos);
- Lisp_Object pos;
-
- eassert (!STRINGP (it->string));
-
- /* If there isn't any `display' property in sight, and no
- overlays, we can just use the position of the newline in
- buffer text. */
- if (it->stop_charpos >= limit
- || ((pos = Fnext_single_property_change (make_fixnum (start),
- Qdisplay, Qnil,
- make_fixnum (limit)),
- NILP (pos))
- && next_overlay_change (start) == ZV))
- {
- if (!it->bidi_p)
- {
- IT_CHARPOS (*it) = limit;
- IT_BYTEPOS (*it) = bytepos;
- }
- else
- {
- struct bidi_it bprev;
-
- /* Help bidi.c avoid expensive searches for display
- properties and overlays, by telling it that there are
- none up to `limit'. */
- if (it->bidi_it.disp_pos < limit)
- {
- it->bidi_it.disp_pos = limit;
- it->bidi_it.disp_prop = 0;
- }
- do {
- bprev = it->bidi_it;
- bidi_move_to_visually_next (&it->bidi_it);
- } while (it->bidi_it.charpos != limit);
- IT_CHARPOS (*it) = limit;
- IT_BYTEPOS (*it) = it->bidi_it.bytepos;
- if (bidi_it_prev)
- *bidi_it_prev = bprev;
- }
- *skipped_p = newline_found_p = true;
- }
- else
- {
- while (!newline_found_p)
- {
- if (!get_next_display_element (it))
- break;
- newline_found_p = ITERATOR_AT_END_OF_LINE_P (it);
- if (newline_found_p && it->bidi_p && bidi_it_prev)
- *bidi_it_prev = it->bidi_it;
- set_iterator_to_next (it, false);
- }
- }
+ *skipped_p = true;
}
it->selective = old_selective;
@@ -8227,8 +8172,9 @@ get_visually_first_element (struct it *it)
if (string_p)
it->bidi_it.charpos = it->bidi_it.bytepos = 0;
else
- it->bidi_it.charpos = find_newline_no_quit (IT_CHARPOS (*it),
- IT_BYTEPOS (*it), -1,
+ it->bidi_it.charpos = find_before_next_newline (IT_CHARPOS (*it),
+ IT_CHARPOS (*it) - MAX_NEWLINE_DISTANCE,
+ -1,
&it->bidi_it.bytepos);
bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true);
do
@@ -10057,7 +10003,7 @@ move_it_vertically_backward (struct it *it, int dy)
ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
DEC_BOTH (cp, bp);
- cp = find_newline_no_quit (cp, bp, -1, NULL);
+ cp = find_before_next_newline (cp, cp - MAX_NEWLINE_DISTANCE, -1, NULL);
move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS);
}
bidi_unshelve_cache (it3data, true);
@@ -24069,7 +24015,7 @@ DEFUN ("bidi-find-overridden-directionality",
itb.bytepos = from_bpos;
}
else
- itb.charpos = find_newline_no_quit (from_pos, CHAR_TO_BYTE (from_pos),
+ itb.charpos = find_before_next_newline (from_pos, from_pos - MAX_NEWLINE_DISTANCE,
-1, &itb.bytepos);
itb.paragraph_dir = NEUTRAL_DIR;
itb.string.s = NULL;