From 76c4aab8345209683496adca5c354d6c737f4c43 Mon Sep 17 00:00:00 2001 From: blinry Date: Wed, 6 Jan 2021 17:04:23 +0100 Subject: [PATCH] Quick implementation of the 3-layer files --- scenes/file_browser.gd | 148 ++++++++++++++++++++-------------- scenes/file_browser_item.gd | 94 ++++++++++++++------- scenes/file_browser_item.tscn | 45 +++++++---- scenes/main.gd | 6 +- scenes/main.tscn | 20 +---- 5 files changed, 187 insertions(+), 126 deletions(-) diff --git a/scenes/file_browser.gd b/scenes/file_browser.gd index da0a284..906c026 100644 --- a/scenes/file_browser.gd +++ b/scenes/file_browser.gd @@ -39,66 +39,94 @@ func substr2(s): return s.substr(2) func update(): - if grid: + if grid and repository: clear() - match mode: - FileBrowserMode.WORKING_DIRECTORY: - if shell: - var wd_files = Array(shell.run("find . -type f").split("\n")) - # The last entry is an empty string, remove it. - wd_files.pop_back() - wd_files = helpers.map(wd_files, self, "substr2") - - var deleted_files = [] - if shell.run("test -d .git && echo yes || echo no") == "yes\n": - deleted_files = Array(shell.run("git status -s | grep '^.D' | sed 's/^...//'").split("\n")) - deleted_files.pop_back() + + # Files in the working directory. + var wd_files = Array(repository.shell.run("find . -type f -not -path '*/\\.git/*'").split("\n")) + # The last entry is an empty string, remove it. + wd_files.pop_back() + wd_files = helpers.map(wd_files, self, "substr2") + + var head_files + var index_files + + if repository.there_is_a_git(): + # Files in the HEAD commit. + head_files = Array(repository.shell.run("git ls-tree --name-only -r HEAD 2> /dev/null || true").split("\n")) + # The last entry is an empty string, remove it. + head_files.pop_back() + # Files in the index. + index_files = Array(repository.shell.run("git ls-files -s | cut -f2 | uniq").split("\n")) + # The last entry is an empty string, remove it. + index_files.pop_back() + + var files = wd_files + for f in head_files: + if not f in files: + files.push_back(f) + for f in index_files: + if not f in files: + files.push_back(f) + + files.sort_custom(self, "very_best_sort") + + for file_path in files: + var item = preload("res://scenes/file_browser_item.tscn").instance() + item.label = file_path + item.repository = repository + item.connect("clicked", self, "item_clicked") + grid.add_child(item) - var files = wd_files + deleted_files - - files.sort_custom(self, "very_best_sort") - #var is_visible = false - for file_path in files: - if file_path.substr(0, 5) == ".git/": - continue - #is_visible = true - var item = preload("res://scenes/file_browser_item.tscn").instance() - item.label = file_path - item.connect("clicked", self, "item_clicked") - item.connect("deleted", self, "item_deleted") - item.status = get_file_status(file_path, shell, 1) - - grid.add_child(item) + if false: + match mode: + FileBrowserMode.WORKING_DIRECTORY: + if shell: + + var deleted_files = [] + if shell.run("test -d .git && echo yes || echo no") == "yes\n": + deleted_files = Array(shell.run("git status -s | grep '^.D' | sed 's/^...//'").split("\n")) + deleted_files.pop_back() + + #var is_visible = false + for file_path in files: + if file_path.substr(0, 5) == ".git/": + continue + #is_visible = true + var item = preload("res://scenes/file_browser_item.tscn").instance() + item.label = file_path + item.connect("clicked", self, "item_clicked") + item.connect("deleted", self, "item_deleted") + item.status = get_file_status(file_path, shell, 1) + + grid.add_child(item) + #visible = is_visible + + FileBrowserMode.COMMIT: + if commit: + # The last entry is an empty string, remove it. + files.pop_back() + for file_path in files: + var item = preload("res://scenes/file_browser_item.tscn").instance() + item.label = file_path + item.connect("clicked", self, "item_clicked") + grid.add_child(item) + FileBrowserMode.INDEX: + #var is_visible = false + if repository and repository.there_is_a_git(): + + var deleted_files = Array(repository.shell.run("git status -s | grep '^D' | sed 's/^...//'").split("\n")) + # The last entries are empty strings, remove them. + + for file_path in files: + var item = preload("res://scenes/file_browser_item.tscn").instance() + item.label = file_path + item.connect("clicked", self, "item_clicked") + item.status = get_file_status(file_path, repository.shell, 0) + grid.add_child(item) + #if item.status != item.IconStatus.NONE: + # is_visible = true #visible = is_visible - - FileBrowserMode.COMMIT: - if commit: - var files = Array(commit.repository.shell.run("git ls-tree --name-only -r %s" % commit.id).split("\n")) - # The last entry is an empty string, remove it. - files.pop_back() - for file_path in files: - var item = preload("res://scenes/file_browser_item.tscn").instance() - item.label = file_path - item.connect("clicked", self, "item_clicked") - grid.add_child(item) - FileBrowserMode.INDEX: - #var is_visible = false - if repository and repository.there_is_a_git(): - var index_files = Array(repository.shell.run("git ls-files -s | cut -f2 | uniq").split("\n")) - var deleted_files = Array(repository.shell.run("git status -s | grep '^D' | sed 's/^...//'").split("\n")) - # The last entries are empty strings, remove them. - index_files.pop_back() - deleted_files.pop_back() - var files = index_files + deleted_files - for file_path in files: - var item = preload("res://scenes/file_browser_item.tscn").instance() - item.label = file_path - item.connect("clicked", self, "item_clicked") - item.status = get_file_status(file_path, repository.shell, 0) - grid.add_child(item) - #if item.status != item.IconStatus.NONE: - # is_visible = true - #visible = is_visible func get_file_status(file_path, the_shell, idx): var file_status = the_shell.run("git status -s '%s'" % file_path) @@ -120,12 +148,12 @@ func get_file_status(file_path, the_shell, idx): return FileBrowserItem.IconStatus.NONE func item_clicked(item): - if item.status == item.IconStatus.REMOVED: + if not item.get_node("VBoxContainer/Control/WD").visible: return match mode: FileBrowserMode.WORKING_DIRECTORY: - text_edit.text = helpers.read_file(shell._cwd + item.label) + text_edit.text = helpers.read_file(repository.shell._cwd + item.label) FileBrowserMode.COMMIT: text_edit.text = commit.repository.shell.run("git show %s:\"%s\"" % [commit.id, item.label]) FileBrowserMode.INDEX: @@ -147,7 +175,7 @@ func close(): func save(): match mode: FileBrowserMode.WORKING_DIRECTORY: - var fixme_path = shell._cwd + var fixme_path = repository.shell._cwd # Add a newline to the end of the file if there is none. if text_edit.text.length() > 0 and text_edit.text.substr(text_edit.text.length()-1, 1) != "\n": diff --git a/scenes/file_browser_item.gd b/scenes/file_browser_item.gd index 1d5285d..4db6078 100644 --- a/scenes/file_browser_item.gd +++ b/scenes/file_browser_item.gd @@ -4,18 +4,50 @@ extends Control signal clicked(what) signal deleted(what) -enum IconStatus {NONE, NEW, REMOVED, CONFLICT, EDIT, UNTRACKED} -export(IconStatus) var status setget _set_status export var label: String setget _set_label var type = "file" +var repository onready var label_node = $VBoxContainer/Label -onready var status_icon = $VBoxContainer/Control/TextureRect/StatusIcon func _ready(): _set_label(label) - _set_status(status) - $PopupMenu.add_item("Delete file", 0) + #$PopupMenu.add_item("Delete file", 0) + var exists_in_wd = repository.shell.run("test -f '%s' && echo yes || echo no" % label) == "yes\n" + var exists_in_index = repository.shell.run("git ls-files --error-unmatch '%s' &>/dev/null && echo yes || echo no" % label) == "yes\n" + var exists_in_head = repository.shell.run("git cat-file -e HEAD:'%s' &>/dev/null && echo yes || echo no" % label) == "yes\n" + + var wd_hash = repository.shell.run("git hash-object '%s' 2>/dev/null || true" % label) + var index_hash = repository.shell.run("git ls-files -s '%s' | cut -f2 -d' '" % label) + var head_hash = repository.shell.run("git ls-tree HEAD '%s' | cut -f1 | cut -f3 -d' '" % label) + + var conflict = Array(index_hash.split("\n")).size() > 2 + + var offset_index = 0 + var offset_wd = 0 + var offset = 10 + + if exists_in_index and exists_in_head and index_hash != head_hash: + offset_index += 1 + + if exists_in_wd and exists_in_head and wd_hash != head_hash: + offset_wd += 1 + + if exists_in_wd and exists_in_index and wd_hash != index_hash and offset_index == offset_wd: + offset_wd += 1 + + $VBoxContainer/Control/Index.rect_position.x += offset_index*offset + $VBoxContainer/Control/Index.rect_position.y -= offset_index*offset + + $VBoxContainer/Control/WD.rect_position.x += offset_wd*offset + $VBoxContainer/Control/WD.rect_position.y -= offset_wd*offset + + if conflict: + $VBoxContainer/Control/Index.self_modulate = Color(1, 0.2, 0.2, 0.5) + + $VBoxContainer/Control/HEAD.visible = exists_in_head + $VBoxContainer/Control/Index.visible = exists_in_index + $VBoxContainer/Control/WD.visible = exists_in_wd func _set_label(new_label): label = new_label @@ -25,33 +57,33 @@ func _set_label(new_label): func _gui_input(event): if event is InputEventMouseButton and event.is_pressed() and event.button_index == BUTTON_LEFT: emit_signal("clicked", self) - if event is InputEventMouseButton and event.is_pressed() and event.button_index == BUTTON_RIGHT and status != IconStatus.REMOVED: - $PopupMenu.set_position(get_global_mouse_position()) - $PopupMenu.popup() +# if event is InputEventMouseButton and event.is_pressed() and event.button_index == BUTTON_RIGHT and status != IconStatus.REMOVED: +# $PopupMenu.set_position(get_global_mouse_position()) +# $PopupMenu.popup() -func _set_status(new_status): - if status_icon: - match new_status: - IconStatus.NEW: - status_icon.texture = preload("res://images/new.svg") - status_icon.modulate = Color("33BB33") - IconStatus.REMOVED: - status_icon.texture = preload("res://images/removed.svg") - status_icon.modulate = Color("D10F0F") - IconStatus.CONFLICT: - status_icon.texture = preload("res://images/conflict.svg") - status_icon.modulate = Color("DE5E09") - IconStatus.EDIT: - status_icon.texture = preload("res://images/modified.svg") - status_icon.modulate = Color("344DED") - IconStatus.UNTRACKED: - status_icon.texture = preload("res://images/untracked.svg") - status_icon.modulate = Color("9209B8") - IconStatus.NONE: - status_icon.texture = null - - status = new_status - +#func _set_status(new_status): +# if status_icon: +# match new_status: +# IconStatus.NEW: +# status_icon.texture = preload("res://images/new.svg") +# status_icon.modulate = Color("33BB33") +# IconStatus.REMOVED: +# status_icon.texture = preload("res://images/removed.svg") +# status_icon.modulate = Color("D10F0F") +# IconStatus.CONFLICT: +# status_icon.texture = preload("res://images/conflict.svg") +# status_icon.modulate = Color("DE5E09") +# IconStatus.EDIT: +# status_icon.texture = preload("res://images/modified.svg") +# status_icon.modulate = Color("344DED") +# IconStatus.UNTRACKED: +# status_icon.texture = preload("res://images/untracked.svg") +# status_icon.modulate = Color("9209B8") +# IconStatus.NONE: +# status_icon.texture = null +# +# status = new_status +# func _popup_menu_pressed(_id): diff --git a/scenes/file_browser_item.tscn b/scenes/file_browser_item.tscn index 82c8cb1..02ca1a5 100644 --- a/scenes/file_browser_item.tscn +++ b/scenes/file_browser_item.tscn @@ -53,13 +53,15 @@ __meta__ = { "_edit_use_anchors_": false } -[node name="TextureRect" type="TextureRect" parent="VBoxContainer/Control"] +[node name="HEAD" type="TextureRect" parent="VBoxContainer/Control"] +self_modulate = Color( 0, 0, 0, 0.317647 ) anchor_right = 1.0 anchor_bottom = 1.0 -margin_left = 8.0 -margin_top = 8.0 -margin_right = -8.0 -margin_bottom = -8.0 +margin_left = -9.54361 +margin_top = 0.372345 +margin_right = -25.5436 +margin_bottom = -15.6277 +rect_scale = Vector2( 1.2, 1.2 ) texture = ExtResource( 3 ) expand = true stretch_mode = 6 @@ -67,15 +69,30 @@ __meta__ = { "_edit_use_anchors_": false } -[node name="StatusIcon" type="TextureRect" parent="VBoxContainer/Control/TextureRect"] -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -margin_left = -11.2842 -margin_top = 0.810516 -margin_right = 13.7158 -margin_bottom = 25.8105 +[node name="Index" type="TextureRect" parent="VBoxContainer/Control"] +self_modulate = Color( 0.54902, 0.45098, 1, 0.654902 ) +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = -1.15317 +margin_top = 4.18617 +margin_right = -17.1532 +margin_bottom = -11.8138 +rect_scale = Vector2( 1.1, 1.1 ) +texture = ExtResource( 3 ) +expand = true +stretch_mode = 6 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="WD" type="TextureRect" parent="VBoxContainer/Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 8.0 +margin_top = 8.0 +margin_right = -8.0 +margin_bottom = -8.0 +texture = ExtResource( 3 ) expand = true stretch_mode = 6 __meta__ = { diff --git a/scenes/main.gd b/scenes/main.gd index 3dda941..d4e4a5d 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -15,7 +15,6 @@ onready var level_description = $Rows/Columns/RightSide/LevelInfo/LevelPanel/Tex onready var level_congrats = $Rows/Columns/RightSide/LevelInfo/LevelPanel/Text/LevelCongrats onready var cards = $Rows/Controls/Cards onready var file_browser = $Rows/Columns/RightSide/FileBrowser -onready var index = $Rows/Columns/RightSide/Index var _hint_server var _hint_client_connection @@ -93,10 +92,8 @@ func load_level(level_id): new_repo.size_flags_horizontal = SIZE_EXPAND_FILL new_repo.size_flags_vertical = SIZE_EXPAND_FILL if new_repo.label == "yours": - file_browser.shell = new_repo.shell + file_browser.repository = new_repo file_browser.update() - index.repository = new_repo - index.update() repositories_node.add_child(new_repo) repositories[r] = new_repo @@ -169,7 +166,6 @@ func update_repos(): var repo = repositories[r] repo.update_everything() file_browser.update() - index.update() func toggle_cards(): cards.visible = not cards.visible diff --git a/scenes/main.tscn b/scenes/main.tscn index 2a5cdb0..a273993 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -84,7 +84,7 @@ custom_constants/separation = 8 [node name="LevelInfo" type="VBoxContainer" parent="Rows/Columns/RightSide"] margin_right = 633.0 -margin_bottom = 383.0 +margin_bottom = 516.0 size_flags_horizontal = 3 size_flags_vertical = 3 custom_constants/separation = 8 @@ -171,7 +171,7 @@ __meta__ = { [node name="LevelPanel" type="VBoxContainer" parent="Rows/Columns/RightSide/LevelInfo"] margin_top = 47.0 margin_right = 633.0 -margin_bottom = 383.0 +margin_bottom = 516.0 size_flags_vertical = 3 [node name="LevelName" type="RichTextLabel" parent="Rows/Columns/RightSide/LevelInfo/LevelPanel"] @@ -187,7 +187,7 @@ __meta__ = { [node name="Text" type="Control" parent="Rows/Columns/RightSide/LevelInfo/LevelPanel"] margin_top = 65.0 margin_right = 633.0 -margin_bottom = 336.0 +margin_bottom = 469.0 size_flags_vertical = 3 [node name="LevelDescription" type="RichTextLabel" parent="Rows/Columns/RightSide/LevelInfo/LevelPanel/Text"] @@ -213,26 +213,14 @@ __meta__ = { "_edit_use_anchors_": false } -[node name="Index" parent="Rows/Columns/RightSide" instance=ExtResource( 5 )] -anchor_right = 0.0 -anchor_bottom = 0.0 -margin_top = 391.0 -margin_right = 633.0 -margin_bottom = 582.0 -size_flags_vertical = 3 -size_flags_stretch_ratio = 0.5 -title = "Plan for the next commit" -mode = 2 - [node name="FileBrowser" parent="Rows/Columns/RightSide" instance=ExtResource( 5 )] anchor_right = 0.0 anchor_bottom = 0.0 -margin_top = 590.0 +margin_top = 524.0 margin_right = 633.0 margin_bottom = 782.0 size_flags_vertical = 3 size_flags_stretch_ratio = 0.5 -title = "Current environment" [node name="Controls" type="HBoxContainer" parent="Rows"] margin_top = 790.0