Created
May 28, 2020 17:40
-
-
Save casouri/7cfab16472a19ae0c786448f0f5e2e6b to your computer and use it in GitHub Desktop.
中英文折行
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Apply the patch to master branch. In Emacs, run
Then enable word-wrap.