aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-05-13 21:25:24 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-05-13 21:25:24 -0700
commitb972b24f3e0a85cd7f7cfe0eb2125ccf4c2efbc3 (patch)
tree0eb9cef8e1ae05cfe75891dbae5360fba9a3bdef
parent72fd3ddba37a2369d52cdacf4f6b29ffba81a0bd (diff)
downloadpw-b972b24f3e0a85cd7f7cfe0eb2125ccf4c2efbc3.tar.gz
pw-b972b24f3e0a85cd7f7cfe0eb2125ccf4c2efbc3.tar.bz2
pw-b972b24f3e0a85cd7f7cfe0eb2125ccf4c2efbc3.zip
New feature: highlight differences between snapshots.
-rw-r--r--pw.147
-rw-r--r--pw.c70
2 files changed, 104 insertions, 13 deletions
diff --git a/pw.1 b/pw.1
index 79a1617..edd613d 100644
--- a/pw.1
+++ b/pw.1
@@ -545,6 +545,46 @@ visualize its most recent output in the
.I pw
display.
+.IP \fBCtrl-D\fI
+Toggle the highlighting of differences between snapshots. When this mode is
+enabled, the currently displayed snapshot is compared to a previous snapshot.
+If any character in the currently displayed snapshot is different from the
+corresponding character of the previous snapshot, or if the previous snapshot
+does not have a corresponding character (because the corresponding line in the
+previous snapshot is shorter), then the character is displayed in inverse
+video.
+
+When the FIFO isn't full, or the snapshot history is empty, display of
+differences is suppressed, even if the mode is enabled.
+
+The moment the first snapshot recedes into a previously empty history, the
+first snapshot becomes the previous snapshot being compared with the current
+snapshot. If no history navigation takes place, then on subsequent snapshots,
+this stays the same: current will be compared with the
+.B "HIST 1"
+snapshot.
+
+When the history is navigated to view the previous snapshots, then the
+previous snapshot is always the previously displayed one which was left
+behind by the position change. For instance, when navigating from the
+.B "HIST 3"
+snapshot to the
+.B "HIST 4"
+snapshot, then 3 becomes the previous reference, and 4 current. The
+display highlights the differences from 3 to 4. Then if a reverse navigation
+step is performed from
+.B "HIST 4"
+back to
+.BR "HIST 3" ,
+then 3 becomes currently displayed and 4 is the previous reference
+snapshot used for comparison: the display highlights the 4 to 3 differences,
+thus chronologically reversed.
+
+Furthermore, As the history window moves due to a new snapshot being taken,
+these positions stay the same. Whatever snapshots are currently 3 and 4 will be
+compared in the order that had been determined by the last navigational
+direction.
+
.SH COLON COMMANDS
First, some general remarks. Display refresh doesn't pause during the editing
@@ -1018,6 +1058,13 @@ will see line number values of zero, which then correct themselves
when the display is refreshed. This is by design, for very good reasons.
Patches to try to fix this will be rejected in the strongest terms.
+Difference highlighting mode is confusing when comparing snapshots that
+overlap, or that are entirely unrelated. The way it is implemented makes it
+primarily useful with snapshots that are triggered and filtered for similarity.
+It doesn't track insertions or deletions of characters; If 999 changes to 1000,
+the rest of the line will be be different, except for characters that are still
+the same by coincidence.
+
.SH AUTHOR
Kaz Kylheku <kaz@kylheku.com>
diff --git a/pw.c b/pw.c
index d1a652f..4c52ab8 100644
--- a/pw.c
+++ b/pw.c
@@ -410,17 +410,28 @@ static void hloff(int *phlite)
hloff(&hlite); \
} while (0)
-static void drawline(pwstate *pw, const char *line, int lineno, char *diffline)
+#define with_hlonoff(onoff, hlite, expr) \
+ do { \
+ (onoff ? hlon : hloff)(&hlite); \
+ expr; \
+ } while(0)
+
+static int diff(const char *line, const char *dline, int dlen, int i)
+{
+ return i >= dlen || line[i] != dline[i];
+}
+
+static void drawline(pwstate *pw, const char *line, int lineno, char *dline)
{
- const char *oline = line;
int olen = (int) dslen(line), len = olen, pos = 0;
+ int dlen = dslen(dline);
int columns = pw->columns;
int vsplit1 = pw->vsplit1;
int vsplit2 = pw->vsplit2;
int vs2pos = pw->vs2pos;
int endmark = 0;
int hlpanel = (pw->stat & stat_hlite) != 0;
- int hldiff = (pw->stat & stat_diff) != 0 && diffline != 0;
+ int hldiff = (pw->stat & stat_diff) != 0 && dline != 0;
int hlite = 0;
if (lineno >= 0)
@@ -429,11 +440,21 @@ static void drawline(pwstate *pw, const char *line, int lineno, char *diffline)
if (vsplit1 > 0) {
if (len <= vsplit1) {
if (!vsplit2) {
- fputs(line, stdout);
+ if (!hldiff)
+ fputs(line, stdout);
+ else
+ for (int i = 0; i < len; i++)
+ with_hlonoff (diff(line, dline, dlen, i), hlite, putchar(line[i]));
columns -= len;
} else {
int spaces = vsplit1 - len;
- fputs(line, stdout);
+ if (!hldiff)
+ fputs(line, stdout);
+ else
+ for (int i = 0; i < len; i++)
+ with_hlonoff (diff(line, dline, dlen, i), hlite, putchar(line[i]));
+ if (spaces)
+ hloff(&hlite);
for (int i = 0; i < spaces; i++)
putchar(' ');
columns -= vsplit1;
@@ -441,8 +462,12 @@ static void drawline(pwstate *pw, const char *line, int lineno, char *diffline)
pos += len;
len = 0;
} else {
- for (int i = 0; i < vsplit1; i++)
- putchar(line[i]);
+ if (!hldiff)
+ for (int i = 0; i < vsplit1; i++)
+ putchar(line[i]);
+ else
+ for (int i = 0; i < vsplit1; i++)
+ with_hlonoff (diff(line, dline, dlen, i), hlite, putchar(line[i]));
len -= vsplit1;
pos += vsplit1;
columns -= vsplit1;
@@ -461,13 +486,19 @@ static void drawline(pwstate *pw, const char *line, int lineno, char *diffline)
if (vs2pos < olen) {
int nchar = min(olen - vs2pos, width);
- const char *ptr = oline + vs2pos + i;
- for (; i < nchar; i++)
- putchar(*ptr++);
+ if (!hldiff)
+ for (; i < nchar; i++)
+ putchar(line[vs2pos + i]);
+ else
+ for (; i < nchar; i++)
+ with_hlonoff (diff(line, dline, dlen, vs2pos + i), hlite,
+ putchar(line[vs2pos + i]));
endmark = 1;
}
if (len > vsplit2 + pw->hpos) {
+ if (i < width)
+ hloff(&hlite);
for (; i < width; i++)
putchar(' ');
@@ -489,12 +520,23 @@ static void drawline(pwstate *pw, const char *line, int lineno, char *diffline)
with_hl (hlpanel, hldiff, hlite, putchar('>'));
columns--;
}
+
if (len < columns) {
- fputs(line + pos, stdout);
+ if (!hldiff)
+ fputs(line + pos, stdout);
+ else
+ for (; pos < olen; pos++)
+ with_hlonoff (diff(line, dline, dlen, pos), hlite,
+ putchar(line[pos]));
clreol(1);
} else {
- for (int i = 0; i < columns - 1; i++)
- putchar(line[pos + i]);
+ if (!hldiff)
+ for (int i = 0; i < columns - 1; i++)
+ putchar(line[pos + i]);
+ else
+ for (int i = 0; i < columns - 1; i++)
+ with_hlonoff (diff(line, dline, dlen, pos + i), hlite,
+ putchar(line[pos + i]));
with_hl (hlpanel, hldiff, hlite, putchar('<'));
putchar('\n');
}
@@ -598,6 +640,8 @@ static void redraw(pwstate *pw)
pw->stat |= stat_susp;
pw->stat &= ~(stat_dirty | stat_trgrd | stat_oneshot);
updln = 1;
+ if (pw->prevhist == 0 && pw->hist == 0)
+ pw->prevhist = 1;
} else if ((pw->stat & stat_force)) {
pw->stat &= ~stat_force;
updln = 1;