mirror of
https://github.com/Relintai/Godot-TextEditor.git
synced 2025-01-26 16:59:19 +01:00
1.11
This commit is contained in:
parent
dfe30486d2
commit
4225903a92
16
CHANGES.md
16
CHANGES.md
@ -1,3 +1,19 @@
|
|||||||
|
# 1.11
|
||||||
|
- Toggled `Low Processor Mode` to keep cpu/gpu usage down.
|
||||||
|
- Simplified *File List* filter display.
|
||||||
|
- *File List* filter now scans closed folders as well.
|
||||||
|
- Folder icon in *File List* changes when open/closed.
|
||||||
|
- *File Editor* now saves states of:
|
||||||
|
- Cursor position.
|
||||||
|
- Selection.
|
||||||
|
- Scroll position.
|
||||||
|
- Enabled hiding in *File Editor*.
|
||||||
|
- *Tag List* tags are sorted.
|
||||||
|
- Added `.rpy` *Renpy* file support.
|
||||||
|
- Added tab/spaces toggle.
|
||||||
|
- Fixed files with `.` in their name not showing up.
|
||||||
|
- Fixed error caused by clicking *File List* symbol for unopened file.
|
||||||
|
|
||||||
# 1.10
|
# 1.10
|
||||||
- Added cursor panel at bottom of Text Editor.
|
- Added cursor panel at bottom of Text Editor.
|
||||||
- Word counter.
|
- Word counter.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Text Editor
|
# Text Editor
|
||||||
Version `1.10`
|
Version `1.11`
|
||||||
|
|
||||||
![](README/readme_preview.png)
|
![](README/readme_preview.png)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ const DNAME_TRASH:String = ".trash"
|
|||||||
const FNAME_STATE:String = ".text_editor_state.json"
|
const FNAME_STATE:String = ".text_editor_state.json"
|
||||||
|
|
||||||
const MAIN_EXTENSIONS:PoolStringArray = PoolStringArray([
|
const MAIN_EXTENSIONS:PoolStringArray = PoolStringArray([
|
||||||
"txt", "md", "json", "csv", "cfg", "ini", "yaml"
|
"txt", "md", "json", "csv", "cfg", "ini", "yaml", "rpy"
|
||||||
])
|
])
|
||||||
const INTERNAL_EXTENSIONS:PoolStringArray = PoolStringArray([
|
const INTERNAL_EXTENSIONS:PoolStringArray = PoolStringArray([
|
||||||
"gd", "tres", "tscn", "import", "gdignore", "gitignore"
|
"gd", "tres", "tscn", "import", "gdignore", "gitignore"
|
||||||
@ -26,6 +26,7 @@ const FILE_FILTERS:PoolStringArray = PoolStringArray([
|
|||||||
"*.cfg ; Config",
|
"*.cfg ; Config",
|
||||||
"*.ini ; Config",
|
"*.ini ; Config",
|
||||||
"*.yaml ; YAML",
|
"*.yaml ; YAML",
|
||||||
|
"*.rpy; Renpy Script"
|
||||||
])
|
])
|
||||||
|
|
||||||
const DIR_COLORS:Dictionary = {
|
const DIR_COLORS:Dictionary = {
|
||||||
@ -289,6 +290,11 @@ func _process(delta):
|
|||||||
progress_bar.visible = false
|
progress_bar.visible = false
|
||||||
set_process(false)
|
set_process(false)
|
||||||
|
|
||||||
|
func get_file_data(file_path:String) -> Dictionary:
|
||||||
|
if not file_path in file_data:
|
||||||
|
update_file_data(file_path)
|
||||||
|
return file_data.get(file_path, {})
|
||||||
|
|
||||||
func update_file_data(file_path:String):
|
func update_file_data(file_path:String):
|
||||||
var helper = get_extension_helper(file_path)
|
var helper = get_extension_helper(file_path)
|
||||||
var text = TE_Util.load_text(file_path)
|
var text = TE_Util.load_text(file_path)
|
||||||
@ -300,6 +306,7 @@ func update_file_data(file_path:String):
|
|||||||
data.tags = ftags
|
data.tags = ftags
|
||||||
file_data[file_path] = data
|
file_data[file_path] = data
|
||||||
|
|
||||||
|
# collect tags
|
||||||
tags.clear()
|
tags.clear()
|
||||||
for d in file_data.values():
|
for d in file_data.values():
|
||||||
for tag in d.tags:
|
for tag in d.tags:
|
||||||
@ -307,8 +314,21 @@ func update_file_data(file_path:String):
|
|||||||
tags[tag] = d.tags[tag]
|
tags[tag] = d.tags[tag]
|
||||||
else:
|
else:
|
||||||
tags[tag] += d.tags[tag]
|
tags[tag] += d.tags[tag]
|
||||||
|
# sort tags
|
||||||
|
var unsorted:Array = []
|
||||||
|
for k in tags:
|
||||||
|
unsorted.append([k, tags[k]])
|
||||||
|
unsorted.sort_custom(self, "_sort_tags")
|
||||||
|
# repopulate
|
||||||
|
tags.clear()
|
||||||
|
for t in unsorted:
|
||||||
|
tags[t[0]] = t[1]
|
||||||
|
|
||||||
emit_signal("tags_updated")
|
emit_signal("tags_updated")
|
||||||
|
|
||||||
|
func _sort_tags(a, b):
|
||||||
|
return a[1] > b[1]
|
||||||
|
|
||||||
# "001_file" -> ["001_", "file"]
|
# "001_file" -> ["001_", "file"]
|
||||||
func _split_header(fname:String):
|
func _split_header(fname:String):
|
||||||
var out = ["", ""]
|
var out = ["", ""]
|
||||||
@ -386,6 +406,7 @@ func save_state():
|
|||||||
"shortcuts": shortcuts,
|
"shortcuts": shortcuts,
|
||||||
|
|
||||||
"file_list": file_list,
|
"file_list": file_list,
|
||||||
|
"file_data": file_data,
|
||||||
|
|
||||||
"div1": $c/div1.split_offset,
|
"div1": $c/div1.split_offset,
|
||||||
"div2": $c/div1/div2.split_offset,
|
"div2": $c/div1/div2.split_offset,
|
||||||
@ -400,6 +421,7 @@ func save_state():
|
|||||||
|
|
||||||
TE_Util.save_json(current_directory.plus_file(FNAME_STATE), state)
|
TE_Util.save_json(current_directory.plus_file(FNAME_STATE), state)
|
||||||
emit_signal("state_saved")
|
emit_signal("state_saved")
|
||||||
|
print("state saved")
|
||||||
|
|
||||||
func load_state():
|
func load_state():
|
||||||
var state:Dictionary = TE_Util.load_json(current_directory.plus_file(FNAME_STATE))
|
var state:Dictionary = TE_Util.load_json(current_directory.plus_file(FNAME_STATE))
|
||||||
@ -421,6 +443,7 @@ func load_state():
|
|||||||
self[k] = state[k]
|
self[k] = state[k]
|
||||||
|
|
||||||
_load_property(state, "file_list")
|
_load_property(state, "file_list")
|
||||||
|
_load_property(state, "file_data")
|
||||||
|
|
||||||
var selected_file:String
|
var selected_file:String
|
||||||
for file_path in state.tabs:
|
for file_path in state.tabs:
|
||||||
@ -428,6 +451,7 @@ func load_state():
|
|||||||
file_path = get_globalized_path(file_path)
|
file_path = get_globalized_path(file_path)
|
||||||
var tab = _open_file(file_path)
|
var tab = _open_file(file_path)
|
||||||
tab.set_state(st)
|
tab.set_state(st)
|
||||||
|
# tab._load_file_data()
|
||||||
if file_path == state.selected:
|
if file_path == state.selected:
|
||||||
selected_file = file_path
|
selected_file = file_path
|
||||||
|
|
||||||
@ -643,7 +667,9 @@ func _menu_view_file(index:int):
|
|||||||
exts_enabled[ext] = not exts_enabled[ext]
|
exts_enabled[ext] = not exts_enabled[ext]
|
||||||
popup_view_file.set_item_checked(index, exts_enabled[ext])
|
popup_view_file.set_item_checked(index, exts_enabled[ext])
|
||||||
else:
|
else:
|
||||||
print("no %s in %s" % [ext, exts_enabled])
|
print("no %s in %s. adding..." % [ext, exts_enabled])
|
||||||
|
exts_enabled[ext] = true
|
||||||
|
popup_view_file.set_item_checked(index, exts_enabled[ext])
|
||||||
|
|
||||||
refresh_files()
|
refresh_files()
|
||||||
save_state()
|
save_state()
|
||||||
@ -1166,7 +1192,7 @@ func _sort_on_ext(a, b):
|
|||||||
static func get_extension(file_path:String) -> String:
|
static func get_extension(file_path:String) -> String:
|
||||||
var file = file_path.get_file()
|
var file = file_path.get_file()
|
||||||
if "." in file:
|
if "." in file:
|
||||||
return file.split(".", true, 1)[1]
|
return file.rsplit(".", true, 1)[1]
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
var complained_ext:Array = []
|
var complained_ext:Array = []
|
||||||
@ -1174,7 +1200,7 @@ var complained_ext:Array = []
|
|||||||
func get_extension_helper(file_path:String) -> TE_ExtensionHelper:
|
func get_extension_helper(file_path:String) -> TE_ExtensionHelper:
|
||||||
var ext:String = get_extension(file_path).replace(".", "_")
|
var ext:String = get_extension(file_path).replace(".", "_")
|
||||||
var ext_path:String = "res://addons/text_editor/ext/ext_%s.gd" % ext
|
var ext_path:String = "res://addons/text_editor/ext/ext_%s.gd" % ext
|
||||||
if ext in ["cfg", "csv", "ini", "json", "md", "yaml", "txt"]:
|
if ext in ["cfg", "csv", "ini", "json", "md", "yaml", "txt", "rpy"]:
|
||||||
return load(ext_path).new()
|
return load(ext_path).new()
|
||||||
|
|
||||||
# only complain once
|
# only complain once
|
||||||
|
@ -39,14 +39,15 @@ func _ready():
|
|||||||
_e = editor.connect("file_renamed", self, "_file_renamed")
|
_e = editor.connect("file_renamed", self, "_file_renamed")
|
||||||
_e = editor.connect("dir_tint_changed", self, "_dir_tint_changed")
|
_e = editor.connect("dir_tint_changed", self, "_dir_tint_changed")
|
||||||
_e = connect("text_changed", self, "text_changed")
|
_e = connect("text_changed", self, "text_changed")
|
||||||
_e = connect("focus_entered", self, "set", ["in_focus", true])
|
_e = connect("focus_entered", self, "_focus_entered")
|
||||||
_e = connect("focus_exited", self, "set", ["in_focus", false])
|
_e = connect("focus_exited", self, "_focus_exited")
|
||||||
_e = connect("mouse_entered", self, "set", ["mouse_inside", true])
|
_e = connect("mouse_entered", self, "set", ["mouse_inside", true])
|
||||||
_e = connect("mouse_exited", self, "set", ["mouse_inside", false])
|
_e = connect("mouse_exited", self, "set", ["mouse_inside", false])
|
||||||
|
# _e = connect("cursor_changed", self, "_cursor_changed")
|
||||||
|
|
||||||
if get_parent() is TabContainer:
|
# if get_parent() is TabContainer:
|
||||||
get_parent().connect("tab_changed", self, "_tab_changed")
|
# get_parent().connect("tab_changed", self, "_tab_changed")
|
||||||
get_parent().connect("tab_selected", self, "_tab_changed")
|
# get_parent().connect("tab_selected", self, "_tab_changed")
|
||||||
|
|
||||||
add_font_override("font", editor.FONT)
|
add_font_override("font", editor.FONT)
|
||||||
var popup = get_menu()
|
var popup = get_menu()
|
||||||
@ -79,6 +80,37 @@ func _ready():
|
|||||||
|
|
||||||
TE_Util.dig(self, self, "_node")
|
TE_Util.dig(self, self, "_node")
|
||||||
|
|
||||||
|
func set_visible(v):
|
||||||
|
prints(file_path, v)
|
||||||
|
.set_visible(v)
|
||||||
|
|
||||||
|
func _focus_entered():
|
||||||
|
if not in_focus:
|
||||||
|
in_focus = true
|
||||||
|
|
||||||
|
func _focus_exited():
|
||||||
|
if in_focus:
|
||||||
|
in_focus = false
|
||||||
|
|
||||||
|
func set_cursor_state(s:Array):
|
||||||
|
cursor_set_line(s[0], s[1])
|
||||||
|
if len(s) > 2:
|
||||||
|
select(s[2], s[3], s[4], s[5])
|
||||||
|
|
||||||
|
func get_cursor_state() -> Array:
|
||||||
|
if is_selection_active():
|
||||||
|
return [
|
||||||
|
cursor_get_line(),
|
||||||
|
cursor_get_column(),
|
||||||
|
get_selection_from_line(),
|
||||||
|
get_selection_from_column(),
|
||||||
|
get_selection_to_line(),
|
||||||
|
get_selection_to_column()]
|
||||||
|
else:
|
||||||
|
return [
|
||||||
|
cursor_get_line(),
|
||||||
|
cursor_get_column()]
|
||||||
|
|
||||||
func _dir_tint_changed(dir:String):
|
func _dir_tint_changed(dir:String):
|
||||||
if file_path.get_base_dir() == dir:
|
if file_path.get_base_dir() == dir:
|
||||||
update_name()
|
update_name()
|
||||||
@ -90,51 +122,25 @@ func _popup_menu(index:int):
|
|||||||
"Capitalize": selection_capitalize()
|
"Capitalize": selection_capitalize()
|
||||||
"Variable": selection_variable()
|
"Variable": selection_variable()
|
||||||
|
|
||||||
var cl
|
|
||||||
var cc
|
|
||||||
var isa
|
|
||||||
var sl1
|
|
||||||
var sc1
|
|
||||||
var sl2
|
|
||||||
var sc2
|
|
||||||
|
|
||||||
func _remember_selection():
|
|
||||||
cl = cursor_get_line()
|
|
||||||
cc = cursor_get_column()
|
|
||||||
isa = is_selection_active()
|
|
||||||
if isa:
|
|
||||||
sl1 = get_selection_from_line()
|
|
||||||
sc1 = get_selection_from_column()
|
|
||||||
sl2 = get_selection_to_line()
|
|
||||||
sc2 = get_selection_to_column()
|
|
||||||
|
|
||||||
func _remake_selection():
|
|
||||||
cursor_set_line(cl)
|
|
||||||
cursor_set_column(cc)
|
|
||||||
if isa:
|
|
||||||
select(sl1, sc1, sl2, sc2)
|
|
||||||
|
|
||||||
func selection_uppercase():
|
func selection_uppercase():
|
||||||
_remember_selection()
|
var s = get_cursor_state()
|
||||||
insert_text_at_cursor(get_selection_text().to_upper())
|
insert_text_at_cursor(get_selection_text().to_upper())
|
||||||
_remake_selection()
|
set_cursor_state(s)
|
||||||
|
|
||||||
func selection_lowercase():
|
func selection_lowercase():
|
||||||
_remember_selection()
|
var s = get_cursor_state()
|
||||||
insert_text_at_cursor(get_selection_text().to_lower())
|
insert_text_at_cursor(get_selection_text().to_lower())
|
||||||
_remake_selection()
|
set_cursor_state(s)
|
||||||
|
|
||||||
func selection_variable():
|
func selection_variable():
|
||||||
_remember_selection()
|
var s = get_cursor_state()
|
||||||
insert_text_at_cursor(TE_Util.to_var(get_selection_text()))
|
insert_text_at_cursor(TE_Util.to_var(get_selection_text()))
|
||||||
_remake_selection()
|
set_cursor_state(s)
|
||||||
|
|
||||||
func selection_capitalize():
|
func selection_capitalize():
|
||||||
_remember_selection()
|
var s = get_cursor_state()
|
||||||
insert_text_at_cursor(get_selection_text().capitalize())
|
insert_text_at_cursor(get_selection_text().capitalize())
|
||||||
_remake_selection()
|
set_cursor_state(s)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _node(n):
|
func _node(n):
|
||||||
var _e
|
var _e
|
||||||
@ -151,17 +157,12 @@ func _scroll_h(h:HScrollBar):
|
|||||||
func _scroll_v(v:VScrollBar):
|
func _scroll_v(v:VScrollBar):
|
||||||
vscroll = v.value
|
vscroll = v.value
|
||||||
|
|
||||||
func _tab_changed(index:int):
|
|
||||||
var myindex = get_index()
|
|
||||||
if index == myindex and visible:
|
|
||||||
# grab_focus()
|
|
||||||
# grab_click_focus()
|
|
||||||
yield(get_tree(), "idle_frame")
|
|
||||||
set_h_scroll(hscroll)
|
|
||||||
set_v_scroll(vscroll)
|
|
||||||
|
|
||||||
func get_state() -> Dictionary:
|
func get_state() -> Dictionary:
|
||||||
var state = { hscroll=scroll_horizontal, vscroll=scroll_vertical }
|
var state = {
|
||||||
|
hscroll=scroll_horizontal,
|
||||||
|
vscroll=scroll_vertical,
|
||||||
|
cursor=get_cursor_state()
|
||||||
|
}
|
||||||
# unsaved
|
# unsaved
|
||||||
if file_path == "":
|
if file_path == "":
|
||||||
state.text = text
|
state.text = text
|
||||||
@ -169,22 +170,21 @@ func get_state() -> Dictionary:
|
|||||||
|
|
||||||
func set_state(state:Dictionary):
|
func set_state(state:Dictionary):
|
||||||
yield(get_tree(), "idle_frame")
|
yield(get_tree(), "idle_frame")
|
||||||
hscroll = state.hscroll
|
|
||||||
vscroll = state.vscroll
|
if "hscroll" in state:
|
||||||
set_h_scroll(state.hscroll)
|
hscroll = state.hscroll
|
||||||
set_v_scroll(state.vscroll)
|
vscroll = state.vscroll
|
||||||
|
set_h_scroll(state.hscroll)
|
||||||
|
set_v_scroll(state.vscroll)
|
||||||
|
|
||||||
if "text" in state:
|
if "text" in state:
|
||||||
if state.text.strip_edges():
|
if state.text.strip_edges():
|
||||||
text = state.text
|
text = state.text
|
||||||
else:
|
else:
|
||||||
editor._close_file(file_path)
|
editor._close_file(file_path)
|
||||||
|
|
||||||
func _file_renamed(old_path:String, new_path:String):
|
if "cursor" in state:
|
||||||
if old_path == file_path:
|
set_cursor_state(state.cursor)
|
||||||
file_path = new_path
|
|
||||||
update_name()
|
|
||||||
update_colors()
|
|
||||||
|
|
||||||
func _update_selected_line():
|
func _update_selected_line():
|
||||||
var l = cursor_get_line()
|
var l = cursor_get_line()
|
||||||
@ -216,6 +216,11 @@ func _input(e):
|
|||||||
if not editor.is_plugin_active():
|
if not editor.is_plugin_active():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# custom tab system
|
||||||
|
if visible and in_focus and e is InputEventKey and e.pressed and e.scancode == KEY_TAB:
|
||||||
|
insert_text_at_cursor(helper.get_tab())
|
||||||
|
get_tree().set_input_as_handled()
|
||||||
|
|
||||||
if not visible or not in_focus or not mouse_inside:
|
if not visible or not in_focus or not mouse_inside:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -314,42 +319,23 @@ func _unhandled_key_input(e):
|
|||||||
helper.toggle_comment(self)
|
helper.toggle_comment(self)
|
||||||
get_tree().set_input_as_handled()
|
get_tree().set_input_as_handled()
|
||||||
|
|
||||||
|
func _file_renamed(old_path:String, new_path:String):
|
||||||
|
if old_path == file_path:
|
||||||
|
file_path = new_path
|
||||||
|
update_name()
|
||||||
|
update_colors()
|
||||||
|
|
||||||
func _file_selected(p:String):
|
func _file_selected(p:String):
|
||||||
if not p:
|
if p != file_path:
|
||||||
return
|
return
|
||||||
|
|
||||||
if p == file_path:
|
update_symbols()
|
||||||
update_symbols()
|
update_heading()
|
||||||
update_heading()
|
|
||||||
|
# yield(get_tree(), "idle_frame")
|
||||||
var cl = cursor_get_line()
|
#
|
||||||
var cc = cursor_get_column()
|
# grab_focus()
|
||||||
var fl
|
# grab_click_focus()
|
||||||
var fc
|
|
||||||
var tl
|
|
||||||
var tc
|
|
||||||
var had_selection = false
|
|
||||||
|
|
||||||
if is_selection_active():
|
|
||||||
had_selection = true
|
|
||||||
fl = get_selection_from_line()
|
|
||||||
fc = get_selection_from_column()
|
|
||||||
tl = get_selection_to_line()
|
|
||||||
tc = get_selection_to_column()
|
|
||||||
|
|
||||||
grab_focus()
|
|
||||||
grab_click_focus()
|
|
||||||
|
|
||||||
yield(get_tree(), "idle_frame")
|
|
||||||
|
|
||||||
cursor_set_line(cl)
|
|
||||||
cursor_set_column(cc)
|
|
||||||
|
|
||||||
if had_selection:
|
|
||||||
select(fl, fc, tl, tc)
|
|
||||||
|
|
||||||
grab_focus()
|
|
||||||
grab_click_focus()
|
|
||||||
|
|
||||||
func goto_symbol(index:int):
|
func goto_symbol(index:int):
|
||||||
var syms = symbols.keys()
|
var syms = symbols.keys()
|
||||||
@ -393,6 +379,8 @@ func set_temporary(t):
|
|||||||
update_name()
|
update_name()
|
||||||
|
|
||||||
func update_symbols():
|
func update_symbols():
|
||||||
|
update_helper()
|
||||||
|
|
||||||
symbols.clear()
|
symbols.clear()
|
||||||
tags.clear()
|
tags.clear()
|
||||||
|
|
||||||
@ -438,12 +426,15 @@ func load_file(path:String):
|
|||||||
clear_undo_history()
|
clear_undo_history()
|
||||||
update_colors()
|
update_colors()
|
||||||
update_name()
|
update_name()
|
||||||
|
|
||||||
func update_colors():
|
func update_helper():
|
||||||
clear_colors()
|
|
||||||
helper = editor.get_extension_helper(file_path)
|
helper = editor.get_extension_helper(file_path)
|
||||||
helper.apply_colors(editor, self)
|
helper.apply_colors(editor, self)
|
||||||
|
|
||||||
|
func update_colors():
|
||||||
|
clear_colors()
|
||||||
|
update_helper()
|
||||||
|
|
||||||
func _created_nonexisting(fp:String):
|
func _created_nonexisting(fp:String):
|
||||||
file_path = fp
|
file_path = fp
|
||||||
modified = false
|
modified = false
|
||||||
|
@ -29,11 +29,11 @@ func _tab_changed(index:int):
|
|||||||
tab = new_tab
|
tab = new_tab
|
||||||
var _e
|
var _e
|
||||||
_e = tab.connect("cursor_changed", self, "_cursor_changed")
|
_e = tab.connect("cursor_changed", self, "_cursor_changed")
|
||||||
_e = tab.connect("text_changed", self, "_text_changed")
|
# _e = tab.connect("text_changed", self, "_text_changed")
|
||||||
|
#
|
||||||
func _text_changed():
|
#func _text_changed():
|
||||||
# print("text changed")
|
## print("text changed")
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
func _input(event):
|
func _input(event):
|
||||||
if event is InputEventKey and event.pressed and tab and is_instance_valid(tab) and tab.has_focus():
|
if event is InputEventKey and event.pressed and tab and is_instance_valid(tab) and tab.has_focus():
|
||||||
|
@ -2,6 +2,7 @@ extends TabContainer
|
|||||||
|
|
||||||
onready var editor:TE_Editor = owner
|
onready var editor:TE_Editor = owner
|
||||||
var mouse:bool = false
|
var mouse:bool = false
|
||||||
|
var last_tab_index:int = -1
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
if not editor.is_plugin_active():
|
if not editor.is_plugin_active():
|
||||||
@ -10,9 +11,42 @@ func _ready():
|
|||||||
var _e
|
var _e
|
||||||
_e = connect("mouse_entered", self, "set", ["mouse", true])
|
_e = connect("mouse_entered", self, "set", ["mouse", true])
|
||||||
_e = connect("mouse_exited", self, "set", ["mouse", false])
|
_e = connect("mouse_exited", self, "set", ["mouse", false])
|
||||||
|
_e = connect("tab_changed", self, "_tab_changed")
|
||||||
|
|
||||||
add_font_override("font", editor.FONT_R)
|
add_font_override("font", editor.FONT_R)
|
||||||
|
|
||||||
|
func _tab_changed(index):
|
||||||
|
var tab
|
||||||
|
var data
|
||||||
|
|
||||||
|
# if last_tab_index >= 0 and last_tab_index < get_child_count():
|
||||||
|
# tab = get_child(last_tab_index)
|
||||||
|
# data = editor.get_file_data(tab.file_path)
|
||||||
|
# data.hscroll = tab.hscroll
|
||||||
|
# data.vscroll = tab.vscroll
|
||||||
|
# data.cursor = tab.get_cursor_state()
|
||||||
|
# prints("SAVED", tab.file_path, tab.cursor_state)
|
||||||
|
#
|
||||||
|
# yield(get_tree(), "idle_frame")
|
||||||
|
#
|
||||||
|
# tab = get_child(index)
|
||||||
|
# data = editor.get_file_data(tab.file_path)
|
||||||
|
# if "cursor" in data:
|
||||||
|
# print("LOADED", data.cursor)
|
||||||
|
# tab.set_cursor_state(data.cursor)
|
||||||
|
# tab.set_h_scroll(data.hscroll)
|
||||||
|
# tab.set_v_scroll(data.vscroll)
|
||||||
|
|
||||||
|
tab = get_child(index)
|
||||||
|
# var s = tab.get_cursor_state()
|
||||||
|
tab.grab_focus()
|
||||||
|
# tab.grab_click_focus()
|
||||||
|
# yield(get_tree(), "idle_frame")
|
||||||
|
# tab.set_cursor_state(s)
|
||||||
|
|
||||||
|
last_tab_index = index
|
||||||
|
# prints(tab, tab.file_path)
|
||||||
|
|
||||||
func _input(e):
|
func _input(e):
|
||||||
if not editor.is_plugin_active():
|
if not editor.is_plugin_active():
|
||||||
return
|
return
|
||||||
|
@ -219,7 +219,7 @@ var lines:PoolStringArray = PoolStringArray()
|
|||||||
|
|
||||||
func _redraw():
|
func _redraw():
|
||||||
lines = PoolStringArray()
|
lines = PoolStringArray()
|
||||||
_draw_dir(editor.file_list[""], 0)
|
lines.append_array(_draw_dir(editor.file_list[""], 0))
|
||||||
set_bbcode(lines.join("\n"))
|
set_bbcode(lines.join("\n"))
|
||||||
|
|
||||||
func _dull_nonwords(s:String, clr:Color, dull:Color) -> String:
|
func _dull_nonwords(s:String, clr:Color, dull:Color) -> String:
|
||||||
@ -235,40 +235,50 @@ func _dull_nonwords(s:String, clr:Color, dull:Color) -> String:
|
|||||||
out += clr(p[1], dull if p[0] else clr)
|
out += clr(p[1], dull if p[0] else clr)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
const FOLDER:String = "🗀" # not visible in godot
|
const FOLDER_CLOSED:String = "🗀" # not visible in Godot.
|
||||||
func _draw_dir(dir:Dictionary, deep:int):
|
const FOLDER_OPEN:String = "🗁" # not visible in Godot.
|
||||||
|
|
||||||
|
func _draw_dir(dir:Dictionary, deep:int) -> Array:
|
||||||
var is_tagging = editor.is_tagging()
|
var is_tagging = editor.is_tagging()
|
||||||
var dimmest:float = .5 if is_tagging else 0.0
|
var dimmest:float = .5 if is_tagging else 0.0
|
||||||
var tint = editor.get_tint_color(dir.tint)
|
var tint = editor.get_tint_color(dir.tint)
|
||||||
var dull = Color.white.darkened(.65)
|
var dull = Color.white.darkened(.65)
|
||||||
var dull_tint = tint.darkened(.5)
|
var dull_tint = tint.darkened(.5)
|
||||||
|
|
||||||
var space = clr("┃ ".repeat(deep), Color.white.darkened(.8))
|
var space = ""
|
||||||
var file:String = dir.file_path
|
var file:String = dir.file_path
|
||||||
|
|
||||||
|
space = clr("┃ ".repeat(deep), Color.white.darkened(.8))
|
||||||
|
|
||||||
var head:String = "▼" if dir.open else "▶"
|
var head:String = "▼" if dir.open else "▶"
|
||||||
head = clr(space+FOLDER, Color.gold) + clr(head, Color.white.darkened(.5))
|
var fold:String = FOLDER_OPEN if dir.open else FOLDER_CLOSED
|
||||||
head += " " + b(_dull_nonwords(file.get_file(), tint.darkened(0 if editor.is_dir_tagged(dir) else 0.5), dull))
|
var dname = b(_dull_nonwords(file.get_file(), tint.darkened(0 if editor.is_dir_tagged(dir) else 0.5), dull))
|
||||||
|
dname = clr("「", dull) + dname + clr("」", dull)
|
||||||
|
head = clr(space+fold, Color.gold) + clr(head, Color.white.darkened(.5))
|
||||||
|
head += " %s" % dname
|
||||||
|
|
||||||
var link:String = meta(head, ["d", dir], editor.get_localized_path(file))
|
var link:String = meta(head, ["d", dir], editor.get_localized_path(file))
|
||||||
if editor.is_trash_path(file):
|
if editor.is_trash_path(file):
|
||||||
link += " " + meta(clr("⬅", Color.yellowgreen), ["unrecycle", dir], file)
|
link += " " + meta(clr("⬅", Color.yellowgreen), ["unrecycle", dir], file)
|
||||||
|
|
||||||
lines.append(link)
|
var out = []
|
||||||
|
|
||||||
var sel = editor.get_selected_tab()
|
var sel = editor.get_selected_tab()
|
||||||
sel = sel.file_path if sel else ""
|
sel = sel.file_path if sel else ""
|
||||||
|
|
||||||
if dir.open:
|
if dir.open or filter:
|
||||||
# draw dirs
|
# draw dirs
|
||||||
for path in dir.dirs:
|
for path in dir.dirs:
|
||||||
var file_path = dir.all[path]
|
var file_path = dir.all[path]
|
||||||
if file_path is Dictionary and file_path.show:
|
if file_path is Dictionary and (file_path.show or filter):
|
||||||
_draw_dir(file_path, deep+1)
|
out.append_array(_draw_dir(file_path, deep+1))
|
||||||
|
|
||||||
# draw files
|
# draw files
|
||||||
var last = len(dir.files)-1
|
var last = len(dir.files)-1
|
||||||
for i in len(dir.files):
|
for i in len(dir.files):
|
||||||
var file_path = dir.files[i]
|
var file_path = dir.files[i]
|
||||||
file = file_path.get_file()
|
var fname = file_path.get_file()
|
||||||
|
file = fname
|
||||||
var p = [file, ""] if not "." in file else file.split(".", true, 1)
|
var p = [file, ""] if not "." in file else file.split(".", true, 1)
|
||||||
file = p[0]
|
file = p[0]
|
||||||
var ext = p[1]
|
var ext = p[1]
|
||||||
@ -276,9 +286,9 @@ func _draw_dir(dir:Dictionary, deep:int):
|
|||||||
var is_selected = file_path == sel
|
var is_selected = file_path == sel
|
||||||
var is_opened = editor.is_opened(file_path)
|
var is_opened = editor.is_opened(file_path)
|
||||||
var color = tint
|
var color = tint
|
||||||
head = "┣╸" if i != last else "┗╸"
|
head = "" if filter else "┣╸" if i != last else "┗╸"
|
||||||
|
|
||||||
var fname_lower = file.to_lower()
|
var fname_lower = fname.to_lower()
|
||||||
|
|
||||||
if "readme" in fname_lower:
|
if "readme" in fname_lower:
|
||||||
head = "🛈"
|
head = "🛈"
|
||||||
@ -308,21 +318,41 @@ func _draw_dir(dir:Dictionary, deep:int):
|
|||||||
line = u(line)
|
line = u(line)
|
||||||
|
|
||||||
var hint_path = editor.get_localized_path(file_path)
|
var hint_path = editor.get_localized_path(file_path)
|
||||||
var symbol_lines = []
|
|
||||||
|
var file_lines = []
|
||||||
|
|
||||||
if not editor._scanning:
|
if not editor._scanning:
|
||||||
var fdata = editor.file_data[file_path]
|
var fdata = editor.get_file_data(file_path)
|
||||||
var symbols = fdata.symbols.values()
|
var symbols = fdata.symbols.values()
|
||||||
for j in range(1, len(symbols)):
|
for j in range(1, len(symbols)):
|
||||||
if fdata.open or filter:
|
if fdata.open or filter:
|
||||||
var sdata = symbols[j]
|
var sdata:Dictionary = symbols[j]
|
||||||
var sname = sdata.name
|
var sname:String = sdata.name
|
||||||
if filter and not filter in sname.to_lower():
|
var index = sname.to_lower().find(filter)
|
||||||
|
|
||||||
|
if filter and index == -1:
|
||||||
continue
|
continue
|
||||||
var s = clr("|%s %s) " % [" ".repeat(sdata.deep), j], dull) + clr(sname, dull_tint)
|
|
||||||
var h = hint_path + " #" + sname
|
var sname_highlighted = TE_Util.highlight(sname, index, len(filter), TE_Util.hue_shift(dull_tint, -.075), Color.white)
|
||||||
symbol_lines.append(meta(space + s, ["fs", file_path, j], h))
|
|
||||||
|
var s = clr(" @ " + "-".repeat(sdata.deep), dull) + sname_highlighted
|
||||||
|
var h = hint_path + " @" + sname
|
||||||
|
file_lines.append(meta(space + s, ["fs", file_path, j], h))
|
||||||
|
|
||||||
if symbol_lines or not (filter and not filter in fname_lower):
|
if filter:
|
||||||
lines.append(meta(space + head + line, ["f", file_path], hint_path))
|
var index = fname_lower.find(filter)
|
||||||
lines.append_array(symbol_lines)
|
if index != -1:
|
||||||
|
line = TE_Util.highlight(fname, index, len(filter), dull_tint, Color.white)
|
||||||
|
|
||||||
|
# show file name if not filtering, or if
|
||||||
|
if not filter or file_lines:
|
||||||
|
file_lines.push_front(meta(space + head + line, ["f", file_path], hint_path))
|
||||||
|
# file_lines.push_front(space + head + line)
|
||||||
|
|
||||||
|
out.append_array(file_lines)
|
||||||
|
|
||||||
|
# show folder name if not filtering, or if filter catches a sub file or subsymbol
|
||||||
|
if not filter or out:
|
||||||
|
out.push_front(link)
|
||||||
|
|
||||||
|
return out
|
||||||
|
@ -73,14 +73,17 @@ func _text_entered(search_for:String):
|
|||||||
var ltext = got_lines[i][2]
|
var ltext = got_lines[i][2]
|
||||||
|
|
||||||
if highlight:
|
if highlight:
|
||||||
var line:String = ltext
|
# var line:String = ltext
|
||||||
var head:String = line.substr(0, char_index)
|
# var head:String = line.substr(0, char_index)
|
||||||
var midd:String = line.substr(char_index, len(search_for))
|
# var midd:String = line.substr(char_index, len(search_for))
|
||||||
var tail:String = line.substr(char_index+len(search_for))
|
# var tail:String = line.substr(char_index+len(search_for))
|
||||||
head = clr(head, Color.white.darkened(.25))
|
# head = clr(head, Color.white.darkened(.25))
|
||||||
midd = b(clr(midd, Color.white))
|
# midd = b(clr(midd, Color.white))
|
||||||
tail = clr(tail, Color.white.darkened(.25))
|
# tail = clr(tail, Color.white.darkened(.25))
|
||||||
l = "\t" + clr(str(lindex) + ": ", Color.white.darkened(.25)) + (head+midd+tail)
|
|
||||||
|
var h = TE_Util.highlight(ltext, char_index, len(search_for), Color.white.darkened(.25), Color.white)
|
||||||
|
|
||||||
|
l = "\t" + clr(str(lindex) + ": ", Color.white.darkened(.25)) + h
|
||||||
|
|
||||||
else:
|
else:
|
||||||
l = "\t" + clr(str(lindex) + ": ", Color.white.darkened(.65)) + clr(ltext, Color.white.darkened(.5))
|
l = "\t" + clr(str(lindex) + ": ", Color.white.darkened(.65)) + clr(ltext, Color.white.darkened(.5))
|
||||||
@ -91,6 +94,8 @@ func _text_entered(search_for:String):
|
|||||||
|
|
||||||
set_bbcode(bbcode.join("\n"))
|
set_bbcode(bbcode.join("\n"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# get a list of files containging lines
|
# get a list of files containging lines
|
||||||
func _search(search_for:String) -> Dictionary:
|
func _search(search_for:String) -> Dictionary:
|
||||||
var out = {}
|
var out = {}
|
||||||
|
@ -26,27 +26,27 @@ func _clicked(args:Array):
|
|||||||
|
|
||||||
editor.enable_tag(tag, not was_enabled)
|
editor.enable_tag(tag, not was_enabled)
|
||||||
|
|
||||||
func sort_tags(tags:Dictionary):
|
#func sort_tags(tags:Dictionary):
|
||||||
var sorter:Array = []
|
# var sorter:Array = []
|
||||||
for tag in tags:
|
# for tag in tags:
|
||||||
sorter.append([tag, tags[tag]])
|
# sorter.append([tag, tags[tag]])
|
||||||
|
#
|
||||||
sorter.sort_custom(self, "_sort_tags")
|
# sorter.sort_custom(self, "_sort_tags")
|
||||||
|
#
|
||||||
tags.clear()
|
# tags.clear()
|
||||||
for item in sorter:
|
# for item in sorter:
|
||||||
tags[item[0]] = item[1]
|
# tags[item[0]] = item[1]
|
||||||
return tags
|
# return tags
|
||||||
|
#
|
||||||
func _sort_tags(a, b):
|
#func _sort_tags(a, b):
|
||||||
return a[0] < b[0]
|
# return a[0] < b[0]
|
||||||
|
|
||||||
func _redraw():
|
func _redraw():
|
||||||
var tab = editor.get_selected_tab()
|
var tab = editor.get_selected_tab()
|
||||||
var tags = editor.tags
|
var tags = editor.tags
|
||||||
var tab_tags = {} if not tab else tab.tags
|
var tab_tags = {} if not tab else tab.tags
|
||||||
|
|
||||||
sort_tags(tags)
|
# sort_tags(tags)
|
||||||
|
|
||||||
if not tags:
|
if not tags:
|
||||||
set_bbcode("[color=#%s][i][center]*No tags*" % [Color.webgray.to_html()])
|
set_bbcode("[color=#%s][i][center]*No tags*" % [Color.webgray.to_html()])
|
||||||
|
@ -200,6 +200,18 @@ static func file_size(path:String) -> String:
|
|||||||
static func hue_shift(c:Color, h:float) -> Color:
|
static func hue_shift(c:Color, h:float) -> Color:
|
||||||
return c.from_hsv(wrapf(c.h + h, 0.0, 1.0), c.s, c.v, c.a)
|
return c.from_hsv(wrapf(c.h + h, 0.0, 1.0), c.s, c.v, c.a)
|
||||||
|
|
||||||
|
static func highlight(line:String, start:int, length:int, default_color:Color, highlight_color:Color) -> String:
|
||||||
|
var head:String = line.substr(0, start)
|
||||||
|
var midd:String = line.substr(start, length)
|
||||||
|
var tail:String = line.substr(start + length)
|
||||||
|
head = clr(head, default_color)
|
||||||
|
midd = b(clr(midd, highlight_color))
|
||||||
|
tail = clr(tail, default_color)
|
||||||
|
return head + midd + tail
|
||||||
|
|
||||||
|
static func b(t:String) -> String: return "[b]%s[/b]" % t
|
||||||
|
static func clr(t:String, c:Color) -> String: return "[color=#%s]%s[/color]" % [c.to_html(), t]
|
||||||
|
|
||||||
#static func saturate(c:Color, s:float=1.0, v:float=1.0) -> Color:
|
#static func saturate(c:Color, s:float=1.0, v:float=1.0) -> Color:
|
||||||
# return c.from_hsv(c.h, c.s * s, c.v * v, c.a)
|
# return c.from_hsv(c.h, c.s * s, c.v * v, c.a)
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ show_line_numbers = true
|
|||||||
draw_tabs = true
|
draw_tabs = true
|
||||||
fold_gutter = true
|
fold_gutter = true
|
||||||
highlight_all_occurrences = true
|
highlight_all_occurrences = true
|
||||||
|
hiding_enabled = true
|
||||||
minimap_draw = true
|
minimap_draw = true
|
||||||
script = ExtResource( 4 )
|
script = ExtResource( 4 )
|
||||||
|
|
||||||
@ -171,7 +172,7 @@ margin_top = 3.0
|
|||||||
margin_right = 1010.0
|
margin_right = 1010.0
|
||||||
margin_bottom = 20.0
|
margin_bottom = 20.0
|
||||||
custom_fonts/font = ExtResource( 12 )
|
custom_fonts/font = ExtResource( 12 )
|
||||||
text = "v1.10"
|
text = "v1.11"
|
||||||
align = 2
|
align = 2
|
||||||
|
|
||||||
[node name="div1" type="HSplitContainer" parent="c"]
|
[node name="div1" type="HSplitContainer" parent="c"]
|
||||||
@ -211,7 +212,7 @@ margin_right = 192.0
|
|||||||
margin_bottom = 27.0
|
margin_bottom = 27.0
|
||||||
custom_fonts/font = ExtResource( 12 )
|
custom_fonts/font = ExtResource( 12 )
|
||||||
clear_button_enabled = true
|
clear_button_enabled = true
|
||||||
placeholder_text = "Filter"
|
placeholder_text = "File Filter"
|
||||||
|
|
||||||
[node name="list_files" type="RichTextLabel" parent="c/div1/c2/c/c"]
|
[node name="list_files" type="RichTextLabel" parent="c/div1/c2/c/c"]
|
||||||
margin_top = 31.0
|
margin_top = 31.0
|
||||||
@ -541,7 +542,7 @@ margin_right = 166.0
|
|||||||
margin_bottom = 27.0
|
margin_bottom = 27.0
|
||||||
custom_fonts/font = ExtResource( 12 )
|
custom_fonts/font = ExtResource( 12 )
|
||||||
clear_button_enabled = true
|
clear_button_enabled = true
|
||||||
placeholder_text = "Filter"
|
placeholder_text = "Symbol Filter"
|
||||||
|
|
||||||
[node name="list_symbols" type="RichTextLabel" parent="c/div1/div2/c2/c/c/c"]
|
[node name="list_symbols" type="RichTextLabel" parent="c/div1/div2/c2/c/c/c"]
|
||||||
margin_top = 31.0
|
margin_top = 31.0
|
||||||
|
@ -4,6 +4,9 @@ class_name TE_ExtensionHelper
|
|||||||
|
|
||||||
var symbols:Dictionary = {}
|
var symbols:Dictionary = {}
|
||||||
|
|
||||||
|
func get_tab() -> String:
|
||||||
|
return " "
|
||||||
|
|
||||||
func generate_meta(t:TextEdit, r:RichTextLabel):
|
func generate_meta(t:TextEdit, r:RichTextLabel):
|
||||||
var chars = TE_Util.commas(len(t.text))
|
var chars = TE_Util.commas(len(t.text))
|
||||||
var words = TE_Util.commas(len(t.text.split(" ", false)))
|
var words = TE_Util.commas(len(t.text.split(" ", false)))
|
||||||
|
50
addons/text_editor/ext/ext_rpy.gd
Normal file
50
addons/text_editor/ext/ext_rpy.gd
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
tool
|
||||||
|
extends TE_ExtensionHelper
|
||||||
|
|
||||||
|
func get_tab() -> String:
|
||||||
|
return " "
|
||||||
|
|
||||||
|
func apply_colors(e:TE_Editor, t:TextEdit):
|
||||||
|
.apply_colors(e, t)
|
||||||
|
|
||||||
|
for k in "label menu define default scene show with play return jump call".split(" "):
|
||||||
|
t.add_keyword_color(k, e.color_symbol)
|
||||||
|
|
||||||
|
# strings
|
||||||
|
t.add_color_region('"', '"', e.color_var)
|
||||||
|
# bools
|
||||||
|
t.add_keyword_color("True", e.color_var)
|
||||||
|
t.add_keyword_color("False", e.color_var)
|
||||||
|
|
||||||
|
# comments
|
||||||
|
t.add_color_region("#", "", e.color_comment, true)
|
||||||
|
t.add_color_region("$ ", "", e.color_comment, true)
|
||||||
|
|
||||||
|
func get_symbols(t:String):
|
||||||
|
var out = .get_symbols(t)
|
||||||
|
var last = add_symbol()
|
||||||
|
var lines = t.split("\n")
|
||||||
|
var i = 0
|
||||||
|
|
||||||
|
while i < len(lines):
|
||||||
|
# symbols
|
||||||
|
if lines[i].begins_with("label "):
|
||||||
|
var key = lines[i].substr(len("label ")).strip_edges()
|
||||||
|
key = key.substr(0, len(key)-1)
|
||||||
|
last = add_symbol(i, 0, key)
|
||||||
|
|
||||||
|
elif lines[i].begins_with("menu "):
|
||||||
|
var key = lines[i].substr(len("menu ")).strip_edges()
|
||||||
|
key = key.substr(0, len(key)-1)
|
||||||
|
last = add_symbol(i, 0, key)
|
||||||
|
|
||||||
|
# tags
|
||||||
|
elif "#" in lines[i]:
|
||||||
|
var p = lines[i].rsplit("#", true, 1)[1]
|
||||||
|
if "#" in p:
|
||||||
|
for tag in p.split("#"):
|
||||||
|
last.tags.append(tag)
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return out
|
@ -3,5 +3,5 @@
|
|||||||
name="TextEditor"
|
name="TextEditor"
|
||||||
description="A text editor for Godot."
|
description="A text editor for Godot."
|
||||||
author="teebar"
|
author="teebar"
|
||||||
version="1.10"
|
version="1.11"
|
||||||
script="plugin.gd"
|
script="plugin.gd"
|
||||||
|
Loading…
Reference in New Issue
Block a user