Skip to content

Instantly share code, notes, and snippets.

@casouri
Created May 28, 2020 17:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save casouri/7cfab16472a19ae0c786448f0f5e2e6b to your computer and use it in GitHub Desktop.
Save casouri/7cfab16472a19ae0c786448f0f5e2e6b to your computer and use it in GitHub Desktop.
中英文折行
From f7c58ba4f67a7c8bcffbb7b7077b10fd944471eb Mon Sep 17 00:00:00 2001
From: Yuan Fu <casouri@gmail.com>
Date: Tue, 26 May 2020 22:47:27 -0400
Subject: [PATCH] checkpoint
---
src/xdisp.c | 131 ++++++++++++++++++++++++++++++++++++----------------
1 file changed, 92 insertions(+), 39 deletions(-)
diff --git a/src/xdisp.c b/src/xdisp.c
index cf15f579b5..e8dd377e6e 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -447,6 +447,7 @@ Copyright (C) 1985-1988, 1993-1995, 1997-2020 Free Software Foundation,
#include "termchar.h"
#include "dispextern.h"
#include "character.h"
+#include "category.h"
#include "buffer.h"
#include "charset.h"
#include "indent.h"
@@ -508,6 +509,39 @@ #define IT_DISPLAYING_WHITESPACE(it) \
&& (*BYTE_POS_ADDR (IT_BYTEPOS (*it)) == ' ' \
|| *BYTE_POS_ADDR (IT_BYTEPOS (*it)) == '\t'))))
+/* These are the category sets we use. */
+#define NOT_AT_EOL 60 /* < */
+#define NOT_AT_BOL 62 /* > */
+#define LINE_BREAKABLE 124 /* | */
+
+/* Return true if the current character allows wrapping before it. */
+static bool char_can_wrap_before (struct it *it)
+{
+ /* We used to only check for whitespace characters for wrapping,
+ hence this macro. You cannot wrap before a space or tab because
+ that way you'll have space and tab at the beginning of next
+ line. */
+ return (!IT_DISPLAYING_WHITESPACE (it)
+ && (it->what == IT_CHARACTER
+ && !CHAR_HAS_CATEGORY(it->c, NOT_AT_BOL)));
+}
+
+/* Return true if the current character allows wrapping after it. */
+static bool char_can_wrap_after (struct it *it)
+{
+ /* We used to only check for whitespace characters for wrapping,
+ hence this macro. Obviously you can wrap after a space or
+ tab. */
+ return (IT_DISPLAYING_WHITESPACE (it)
+ || (it->what == IT_CHARACTER
+ && CHAR_HAS_CATEGORY (it->c, LINE_BREAKABLE)
+ && !CHAR_HAS_CATEGORY(it->c, NOT_AT_EOL)));
+}
+
+#undef NOT_AT_BOL
+#undef NOT_AT_BOL
+#undef LINE_BREAKABLE
+
/* If all the conditions needed to print the fill column indicator are
met, return the (nonnegative) column number, else return a negative
value. */
@@ -9185,13 +9219,14 @@ #define IT_RESET_X_ASCENT_DESCENT(IT) \
{
if (it->line_wrap == WORD_WRAP && it->area == TEXT_AREA)
{
- if (IT_DISPLAYING_WHITESPACE (it))
- may_wrap = true;
- else if (may_wrap)
+ /* Can we wrap here? */
+ if (may_wrap && char_can_wrap_before(it))
{
/* We have reached a glyph that follows one or more
- whitespace characters. If the position is
- already found, we are done. */
+ whitespace characters or a character that allows
+ wrapping after it. If this character allows
+ wrapping before it, save this position as a
+ wrapping point. */
if (atpos_it.sp >= 0)
{
RESTORE_IT (it, &atpos_it, atpos_data);
@@ -9206,8 +9241,17 @@ #define IT_RESET_X_ASCENT_DESCENT(IT) \
}
/* Otherwise, we can wrap here. */
SAVE_IT (wrap_it, *it, wrap_data);
- may_wrap = false;
}
+ /* This has to run after the previous block because the
+ previous block consumes `may_wrap' and this block
+ sets it, but the value set by this block is intended
+ for the _next_ character/iteration. */
+ if (char_can_wrap_after (it))
+ /* may_wrap basically means "previous char allows
+ wrapping after it". */
+ may_wrap = true;
+ else
+ may_wrap = false;
}
}
@@ -9335,10 +9379,10 @@ #define IT_RESET_X_ASCENT_DESCENT(IT) \
{
bool can_wrap = true;
- /* If we are at a whitespace character
- that barely fits on this screen line,
- but the next character is also
- whitespace, we cannot wrap here. */
+ /* If the previous character says we can
+ wrap after it, but the current
+ character says we can't wrap before
+ it, then we can't wrap here. */
if (it->line_wrap == WORD_WRAP
&& wrap_it.sp >= 0
&& may_wrap
@@ -9350,7 +9394,7 @@ #define IT_RESET_X_ASCENT_DESCENT(IT) \
SAVE_IT (tem_it, *it, tem_data);
set_iterator_to_next (it, true);
if (get_next_display_element (it)
- && IT_DISPLAYING_WHITESPACE (it))
+ && !char_can_wrap_before(it))
can_wrap = false;
RESTORE_IT (it, &tem_it, tem_data);
}
@@ -9429,19 +9473,18 @@ #define IT_RESET_X_ASCENT_DESCENT(IT) \
else
IT_RESET_X_ASCENT_DESCENT (it);
- /* If the screen line ends with whitespace, and we
- are under word-wrap, don't use wrap_it: it is no
- longer relevant, but we won't have an opportunity
- to update it, since we are done with this screen
- line. */
+ /* If the screen line ends with whitespace (or
+ wrap-able character), and we are under word-wrap,
+ don't use wrap_it: it is no longer relevant, but
+ we won't have an opportunity to update it, since
+ we are done with this screen line. */
if (may_wrap && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)
/* If the character after the one which set the
- may_wrap flag is also whitespace, we can't
- wrap here, since the screen line cannot be
- wrapped in the middle of whitespace.
- Therefore, wrap_it _is_ relevant in that
- case. */
- && !(moved_forward && IT_DISPLAYING_WHITESPACE (it)))
+ may_wrap flag says we can't wrap before it,
+ we can't wrap here. Therefore, wrap_it
+ (previously found wrap-point) _is_ relevant
+ in that case. */
+ && !(moved_forward && char_can_wrap_before(it)))
{
/* If we've found TO_X, go back there, as we now
know the last word fits on this screen line. */
@@ -23292,9 +23335,8 @@ #define RECORD_MAX_MIN_POS(IT) \
if (it->line_wrap == WORD_WRAP && it->area == TEXT_AREA)
{
- if (IT_DISPLAYING_WHITESPACE (it))
- may_wrap = true;
- else if (may_wrap)
+ /* Can we wrap here? */
+ if (may_wrap && char_can_wrap_before(it))
{
SAVE_IT (wrap_it, *it, wrap_data);
wrap_x = x;
@@ -23308,9 +23350,13 @@ #define RECORD_MAX_MIN_POS(IT) \
wrap_row_min_bpos = min_bpos;
wrap_row_max_pos = max_pos;
wrap_row_max_bpos = max_bpos;
- may_wrap = false;
}
- }
+ /* This has to run after the previous block. */
+ if (char_can_wrap_after (it))
+ may_wrap = true;
+ else
+ may_wrap = false;
+ }
}
PRODUCE_GLYPHS (it);
@@ -23433,14 +23479,18 @@ #define RECORD_MAX_MIN_POS(IT) \
/* If line-wrap is on, check if a previous
wrap point was found. */
if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)
- && wrap_row_used > 0
+ && wrap_row_used > 0 /* Found. */
/* Even if there is a previous wrap
point, continue the line here as
usual, if (i) the previous character
- was a space or tab AND (ii) the
- current character is not. */
- && (!may_wrap
- || IT_DISPLAYING_WHITESPACE (it)))
+ allows wrapping after it, AND (ii)
+ the current character allows wrapping
+ before it. Because this is a valid
+ break point, we can just continue to
+ the next line at here, there is no
+ need to wrap early at the previous
+ wrap point. */
+ && (!may_wrap || !char_can_wrap_before(it)))
goto back_to_wrap;
/* Record the maximum and minimum buffer
@@ -23468,13 +23518,16 @@ #define RECORD_MAX_MIN_POS(IT) \
/* If line-wrap is on, check if a
previous wrap point was found. */
else if (wrap_row_used > 0
- /* Even if there is a previous wrap
- point, continue the line here as
- usual, if (i) the previous character
- was a space or tab AND (ii) the
- current character is not. */
- && (!may_wrap
- || IT_DISPLAYING_WHITESPACE (it)))
+ /* Even if there is a previous
+ wrap point, continue the
+ line here as usual, if (i)
+ the previous character was a
+ space or tab AND (ii) the
+ current character is not,
+ AND (iii) the current
+ character allows wrapping
+ before it. */
+ && (!may_wrap || !char_can_wrap_before(it)))
goto back_to_wrap;
}
--
2.26.1
@casouri
Copy link
Author

casouri commented May 28, 2020

Apply the patch to master branch. In Emacs, run

(load "kinsoku.el)

Then enable word-wrap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment