Skip to content

Commit

Permalink
Add patch/diff file highlighting
Browse files Browse the repository at this point in the history
Added patch/diff file highlighting for easy at a glance viewing.

Does not try to highlight based on language, just a simple green for additions
and red for deletions, plus some extra colours for metadata.

(This could be changed in the future if we did want to highlight per language
since the regions I added could stay the same and just change the token
colours... That would involve needing to detect language based on the file
extensions of the diff'd files though which might be kind of slow, especially
for large patches that involve many files.)
  • Loading branch information
SentientCoffee committed Feb 21, 2025
1 parent 948529b commit d43050d
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/buffer.jai
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,7 @@ get_tokenize_function :: (lang: Buffer.Lang) -> Tokenize_Function {
case .Css; return tokenize_css;
case .CSharp; return tokenize_csharp;
case .D; return tokenize_d;
case .Diff; return tokenize_diff;
case .Glsl; return tokenize_glsl;
case .Hlsl; return tokenize_hlsl;
case .Golang; return tokenize_golang;
Expand Down Expand Up @@ -1839,6 +1840,7 @@ Buffer :: struct {
Css;
CSharp;
D;
Diff;
Glsl;
Hlsl;
Golang;
Expand Down Expand Up @@ -1914,6 +1916,9 @@ Buffer_Region :: struct {
scope_module;

heredoc;

addition;
deletion;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/colors.jai
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ Color :: enum u8 {
REGION_WARNING;
REGION_ERROR;
REGION_HEREDOC;
REGION_ADDITION;
REGION_DELETION;

BUILD_PANEL_BACKGROUND;
BUILD_PANEL_SCROLLBAR;
Expand Down
2 changes: 1 addition & 1 deletion src/config.jai
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Increment this if your PR adds a setting, color or default keybinding (and amend the relevant array
// in config_migrator.jai). You don't need to increase it for each such change; once per PR is fine.
CURRENT_CONFIG_VERSION :: 16;
CURRENT_CONFIG_VERSION :: 17;

load_global_config :: (fallback_to_default_on_failure := false, force := false) -> success: bool, changed: bool, there_were_warnings: bool {
config_path := tprint("%/global.focus-config", config_dir);
Expand Down
5 changes: 5 additions & 0 deletions src/config_migrator.jai
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,11 @@ ADDED_COLORS :: Added_Color.[

.{ 8, "bracket_highlight", "selection_highlight", "E8FCFE30" },
.{ 8, "indent_guide", "selection_highlight", "FCEDFC26" },

.{ 17, "code_addition", "", "33B333FF" },
.{ 17, "region_addition", "", "2260224C" },
.{ 17, "code_deletion" , "", "E64D4DFF" },
.{ 17, "region_deletion", "", "7722224C" },
];


Expand Down
2 changes: 2 additions & 0 deletions src/config_parser.jai
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ map_name_to_color :: (name: string) -> Color {
case "region_warning"; return .REGION_WARNING;
case "region_error"; return .REGION_ERROR;
case "region_heredoc"; return .REGION_HEREDOC;
case "region_addition"; return .REGION_ADDITION;
case "region_deletion"; return .REGION_DELETION;

case "build_panel_background"; return .BUILD_PANEL_BACKGROUND;
case "build_panel_scrollbar"; return .BUILD_PANEL_SCROLLBAR;
Expand Down
2 changes: 2 additions & 0 deletions src/draw.jai
Original file line number Diff line number Diff line change
Expand Up @@ -3889,6 +3889,8 @@ get_region_color :: (kind: Buffer_Region.Kind) -> Color {
case .success; color = Color.REGION_SUCCESS;
case .warning; color = Color.REGION_WARNING;
case .error; color = Color.REGION_ERROR;
case .addition; color = Color.REGION_ADDITION;
case .deletion; color = Color.REGION_DELETION;
}
return color;
}
Expand Down
5 changes: 5 additions & 0 deletions src/editors.jai
Original file line number Diff line number Diff line change
Expand Up @@ -1347,6 +1347,9 @@ get_lang_from_path :: (full_path: string) -> Buffer.Lang {

case "ini"; lang = .Ini;

case "diff"; lang = .Diff;
case "patch"; lang = .Diff;

case;
// Files named `.focus_config` are assumed to have no extension
if equal_nocase(basename_with_extension, ".focus-config") then lang = .Focus_Config;
Expand Down Expand Up @@ -3483,6 +3486,7 @@ toggle_comment :: (editor: *Editor, buffer: *Buffer, is_fallback := false) {
// No support for comments at all
case .Plain_Text; #through;
case .Todo; #through;
case .Diff; #through;
case .Focus_Build_Panel;
return;
}
Expand Down Expand Up @@ -3712,6 +3716,7 @@ toggle_block_comment :: (editor: *Editor, buffer: *Buffer, is_fallback := false)
// No support for comments at all
case .Plain_Text; #through;
case .Todo; #through;
case .Diff; #through;
case .Focus_Build_Panel;
return;
}
Expand Down
3 changes: 3 additions & 0 deletions src/langs/common.jai
Original file line number Diff line number Diff line change
Expand Up @@ -357,4 +357,7 @@ Token_Type :: enum u8 {
header4;
header5;
header6;

addition;
deletion;
}
145 changes: 145 additions & 0 deletions src/langs/diff.jai
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
tokenize_diff :: (using buffer: *Buffer, start_offset := -1, count := -1) -> [] Buffer_Region {
tokenizer: Diff_Tokenizer;
tokenizer.base = get_tokenizer(buffer, start_offset, count);

while true {
token := get_next_token(*tokenizer);
if token.type == .eof break;

memset(tokens.data + token.start, xx token.type, token.len);
}

if tokenizer.current_region_id >= 0 then end_region(*tokenizer, tokenizer.t - tokenizer.buf.data);
quick_sort(tokenizer.regions, (a, b) => (a.start - b.start));
return tokenizer.regions;
}

#scope_file

get_next_token :: (using tokenizer: *Diff_Tokenizer) -> Token {
token := Token.{
start = cast(s32) (t - buf.data),
type = .eof,
};

if t >= max_t return token;

start_t = t;
char := t.*;

if char == {
case #char "+"; parse_plus (tokenizer, *token);
case #char "-"; parse_minus (tokenizer, *token);
case #char "@"; parse_range (tokenizer, *token);
case #char " "; parse_unchanged(tokenizer, *token);
case; parse_metadata (tokenizer, *token);
}

if t >= max_t then t = max_t;
token.len = cast(s32) (t - start_t);
return token;
}

parse_plus :: (using tokenizer: *Diff_Tokenizer, token: *Token) {
token.type = .addition;

t += 1;
if t >= max_t then return;

current := t.*;
next := (t + 1).*;
if current == #char "+" && next == #char "+" {
eat_until_newline(tokenizer);
t += 1;
}
else {
if current_region_id == -1 || regions[current_region_id].kind != .addition {
start_region(tokenizer, token.start, .addition);
}
eat_until_newline(tokenizer);
t += 1;
}

if t > max_t then t = max_t;
}

parse_minus :: (using tokenizer: *Diff_Tokenizer, token: *Token) {
token.type = .deletion;

t += 1;
if t >= max_t then return;

current := t.*;
next := (t + 1).*;
if current == #char "-" && next == #char "-" {
eat_until_newline(tokenizer);
t += 1;
}
else {
if current_region_id == -1 || regions[current_region_id].kind != .deletion {
start_region(tokenizer, token.start, .deletion);
}
eat_until_newline(tokenizer);
t += 1;
}

if t > max_t then t = max_t;
}

parse_range :: (using tokenizer: *Diff_Tokenizer, token: *Token) {
t += 1;
if t >= max_t || t.* != #char "@" {
parse_metadata(tokenizer, token);
return;
}

token.type = .number;
if current_region_id != -1 then end_region(tokenizer, token.start);
eat_until_newline(tokenizer);
t += 1;
}

parse_unchanged :: (using tokenizer: *Diff_Tokenizer, token: *Token) {
token.type = .identifier;
if current_region_id != -1 then end_region(tokenizer, token.start);
eat_until_newline(tokenizer);
t += 1;
}

parse_metadata :: (using tokenizer: *Diff_Tokenizer, token: *Token) {
token.type = .string_literal;
if current_region_id != -1 then end_region(tokenizer, token.start);
eat_until_newline(tokenizer);
t += 1;
}

start_region :: (using tokenizer: *Diff_Tokenizer, offset: s64, kind: Buffer_Region.Kind) {
if current_region_id >= 0 then end_region(tokenizer, offset);
current_region_id = regions.count;

region := Buffer_Region.{
start = xx offset,
end = -1,
kind = kind,
};
array_add(*regions, region);
}

end_region :: inline (using tokenizer: *Diff_Tokenizer, offset: s64) {
regions[current_region_id].end = xx offset;
current_region_id = -1;
}

Diff_Tokenizer :: struct {
using #as base: Tokenizer;

regions: [..] Buffer_Region;
regions.allocator = temp;
current_region_id := -1;
}

Token :: struct {
start, len: s32;
type: Token_Type;
}

1 change: 1 addition & 0 deletions src/main.jai
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,7 @@ focus_allocator: Allocator;
#load "langs/batch.jai";
#load "langs/swift.jai";
#load "langs/ini.jai";
#load "langs/diff.jai";

#if OS == .WINDOWS {
#load "platform/windows.jai";
Expand Down
1 change: 1 addition & 0 deletions src/widgets/color_preview.jai
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ get_language_sample_text :: (lang: Buffer.Lang) -> string {
case .Css; return SAMPLE_Css;
case .CSharp; return SAMPLE_CSharp;
case .D; return SAMPLE_D;
case .Diff; return SAMPLE_Diff;
case .Glsl; return SAMPLE_Glsl;
case .Hlsl; return SAMPLE_Hlsl;
case .Golang; return SAMPLE_Golang;
Expand Down
63 changes: 61 additions & 2 deletions src/widgets/color_preview_samples.jai
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,8 @@ main :: proc() {
}

Structure :: struct {
is_true: bool,
text: string,
is_true: bool,
text: string,
}

ODIN
Expand Down Expand Up @@ -1251,3 +1251,62 @@ lines"
StillOk = true

LANG_INI

SAMPLE_Diff :: #string LANG_Diff
diff --git a/src/draw.jai b/src/draw.jai
index 6711110..e7b4234 100644
--- a/src/draw.jai
+++ b/src/draw.jai
@@ -3761,7 +3761,7 @@ get_new_scroll_target_from_scrollbar :: (main_rect: Rect, content_height: float,
draw_scrollbar :: (main_rect: Rect, content_height: float, scroll: s32, scroll_target: s32, max_scroll: s32, ui_id: Ui_Id, for_build_panel := false, $draw := true) -> new_scroll_target: s32 {
scroll_target = clamp(scroll_target, 0, max_scroll);

- if scroll != scroll_target then start_scrollbar_fade_out_animation(ui_id, initial_value = config.settings.scrollbar_max_opacity);
+ if scroll != scroll_target then start_scrollbar_fade_out_animation(ui_id);

if max_scroll <= 0 return scroll_target;

@@ -3955,7 +3955,9 @@ is_hovering_over :: (ui_id: Ui_Id) -> bool {
return (ui.hot_last_frame == ui_id && ui.active == .none) || ui.active == ui_id;
}

-start_scrollbar_fade_out_animation :: (ui_id: Ui_Id, initial_value := 1.0) {
+start_scrollbar_fade_out_animation :: (ui_id: Ui_Id, initial_value := -1.0) {
+ if initial_value < 0 then initial_value = config.settings.scrollbar_max_opacity;
+
animation: *Scrollbar_Fade_Out_Animation;
for * scrollbar_fade_out_animations {
if it.ui_id == ui_id { animation = it; break; }
@@ -3967,6 +3969,7 @@ start_scrollbar_fade_out_animation :: (ui_id: Ui_Id, initial_value := 1.0) {
start_animation(*animation.anim, initial_value, 0.0, delay = config.settings.scrollbar_fade_out_delay_seconds);
}

+
#scope_export

Icon :: enum u16 {
diff --git a/src/editors.jai b/src/editors.jai
index fa5ae21..3bc8ebf 100644
--- a/src/editors.jai
+++ b/src/editors.jai
@@ -2320,13 +2320,15 @@ move_cursors_by_page :: (editor: *Editor, buffer: Buffer, dir: enum { up; down;
page_size := cast(s32) (window_height / line_height);

for * cursor : editor.cursors {
- line := offset_to_line(editor, buffer, cursor.pos);
+ coords := offset_to_coords(editor, buffer, cursor.pos);
if dir == .up {
- line -= page_size;
+ coords.line -= page_size;
} else {
- line += page_size;
+ coords.line += page_size;
}
- cursor.pos = coords_to_offset(editor, buffer, Coords.{ line = line, col = cursor.col_wanted });
+ if cursor.col_wanted < 0 then cursor.col_wanted = coords.col;
+ coords.col = cursor.col_wanted;
+ cursor.pos = coords_to_offset(editor, buffer, coords);
}

if dir == .up editor.cursor_moved = .moved_up;
LANG_Diff

0 comments on commit d43050d

Please sign in to comment.