Compare commits

..

No commits in common. "main" and "v1.1" have entirely different histories.
main ... v1.1

50 changed files with 1131 additions and 3868 deletions

1
.gitignore vendored
View File

@ -16,4 +16,3 @@ test_files/
.trash/ .trash/
.trash.json .trash.json
.text_editor_state.json .text_editor_state.json
word_skip_list.txt

View File

@ -1,149 +1,6 @@
# 1.12
- Changed icon.
- Added tabs popup menu:
- Options for closing many tabs.
- Options for selecting tabs.
- Console is hidden on start.
- Fixed `yaml` tabs not working.
- Fixed `tab` + `shift + tab`ing when multiple lines are selected.
# 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
- Added cursor panel at bottom of Text Editor.
- Word counter.
- Symbol path.
- Added `insert` menu, for inserting Date.
- `ctrl + shift + u` and `ctrl + shift + l` will toggle uppercase and lowercase.
- `ctrl + shift + o` and `ctrl + shift + p` will toggle capitalize and variablize.
- Fixed `ctrl + f` not bringing up search pannel.
- Fixed error when creating new file.
- Removed Text Editor hints.
- Color tweaks.
# 1.9
- Tag Viewer now shows all tags regardless of whether the file is open or not.
- File View can show symbols. Toggle with `ctrl` click.
- File View filter will scan symbols as well.
- File List dims characters `0123456789-_`.
- Image Preview on `ctrl + click` in Markdown: `![](icon.png)` will display `"res://icon.png"`
- Tab title ignores leading numbers: "001_character" = "character"
- Directories are highlighted if they have a file with a selected tag.
- Holding `ctrl` while selecting a tag allows multiple to be selected.
- Added tab icon based on folder color.
- Fixed Markdown symbol generator including `#` inside code.
- Fixed meta container resizing.
# 1.8
- Added filter to symbols list.
- Added filter to file list.
- Added `.md` highlighting for `{}`. (Not official Markdown.)
- Fixed unsaved files asking for a save path if no text entered.
- Fixed file wiping if hitting undo after loading a file.
- Fixed *no word_skip_list.txt* error.
- Folders colorized in file list.
- Display version at top right.
# 1.7
- Added option to view `Extensionless` files.
- Added Symbol path heirarchy to hint popup so you know where you are in big files:
![](README/changes_hint_toc.png)
- `ctrl + shift +`
- `U` Make selection uppercase.
- `L` Make selection lowercase.
- `O` Make selection capitalized.
- `P` Make selection variable: `My text -> my_text`
- Select file shorctut:
- `ctrl + shift + 0-9` Remember file.
- `ctrl + 0-9` Swap to file.
- Selected Symbol is now highlighted.
- Improved meta data for `.md` files.
- `search` will autoselect term when clicked.
- `search` `all` toggle added to allow only searching in the selected file.
- `search` `case` toggle added to allow searching based on upper/lower case.
- `sys` panel shows unique word list.
- `sys` panel shows time since modified.
- Can create a `word_skip_list.txt` in main folder for ignoring certain words from showing in `sys` word list.
- File List panel hint paths are localized.
- Removed `.md` function color.
- Fixed `trash` not working in exported binaries.
- Fixed dragging files into directory bug.
- Fixed temporary files not closing properly.
- Fixed close non existing tab bug.
- Fixed symbol list not redrawing after file closed.
- Fixed symbol list not redrawing after file type changed.
- Fixed focus not being grabbed when tab selected.
# 1.6
- Added `Uppercase` `Lowercase` and `Capitalize` option to popup menu for selected text.
- `ctrl + click` in Symbol View selects entire "chapter" and sub "chapters". `ctrl + shift + click` selects only one "chapter".
- `ctrl + click` in editor will auto scroll symbol view.
- Folders can be tinted.
- `word_wrap` state is saved/loaded.
- Fixed error that occured when folder containing binary was moved.
- Markdown can have a `progress` field in meta data which can be sorted in `sys`.
- Markdown meta info taken into account for `sys`
- Markdown meta info colourized.
- Markdown code color based on variable color.
- JSON comments like YAML: `"#": "comment"`
- JSON color tweaks.
# 1.5
- Added `Ctrl + N` to immediately create new file without defining path.
- New unsaved file will have contents remembered.
- Added `Ctrl + Shift + Mouse wheel` to change ui font size.
- Added word wrap toggle.
- Fixed sorting error in `sys`.
- Fixed font size save/load.
- `sys` shows chapter count.
- Preserves symbol view scroll value when tabbing.
- Can access full filesystem.
- Fixed "New File" dialog not gaining focus.
# 1.4
- Added `sys` info tab.
- Added `console` info tab. (wip)
- Changing extension updates colors.
- Fixed exported build not styling things properly.
- Fixed symbols/tags not showing when first booting editor.
- Tweaked colors.
- Internal rewriting.
# 1.3
- Basic search implemented. `Ctrl + F`
- Can create links inside `()` which makes markdown links clickable.: `Ctrl + Click`
# 1.2
- Can unrecycle now. (Make sure `view/Directories/.trash` is toggled, then press arrow.
- Added folder recycle option
- Added folder move/drag.
- Empty directories properly hide if they have no subdirectories.
- Fixed hide/show file type not updating list.
- Settings are saved more frequently.
- Fixed file dragging.
- Fixed meta table not resizing.
- Tweaked symbol colorizer to emphasize depth.
- Bug fixes.
# 1.1 # 1.1
- Added `addons` folder hider option.
- Preserve folder open/close state.
- Fixed directories with `.gdignore` not hiding.
- Fixed files and directories not being sorted. - Fixed files and directories not being sorted.
- Added `addons` folder hider option.
- Fixed "failed to load settings" error. - Fixed "failed to load settings" error.
- Tweaked syntax coloring. - Tweaked syntax coloring.
- Got rid of accidental test file. - Got rid of accidental test file.

154
README.md
View File

@ -1,62 +1,48 @@
# Text Editor # Text Editor
Version `1.12` Version 1.1
![](README/readme_preview.png) ![](README/readme_preview.png)
***Warning: Use at your own risk. Backup your files before testing.*** ***Warning: Use at your own risk. Backup your files before testing.***
# Features # Features
- Multi file tab system. - Tabs with scroll
- File browser filtering. - File filtering
- Highlighting for common formats (`md` `json` `ini`...) - Highlighting for common file formats (`md` `json`...)
- Tag [System](#mini-features-tags). - Tag filtering system
- File Management: - File Management:
- Creation. - Creation
- Renaming. - Renaming
- Recycling. - Recycling
- Moving. - Auto save/load settings
- Search files. - Many little *Ease of life* functions:
- Image previews. - Folder open/close
- Auto save/load settings. - Comment toggling for:
- Many little *Ease of Life* [features](#mini-features). - `.md`: `<!-- -->`
- `.json`: `/* */`
- `.ini`: `; `
- `.cfg`: `; `
- `.yaml`: `# `
# Controls # Controls
- `ctrl + N` New file. - `ctrl + W` Close file
- `ctrl + W` Close file. - `ctrl + shift + W` Open last closed file
- `ctrl + shift + W` Open last closed file . - `ctrl + tab` Select next open file
- `ctrl + tab` Select next open file. - `ctrl + shift + tab` Select last open file
- `ctrl + shift + tab` Select last open file. - `ctrl + mouse wheel` Adjust font size
- `ctrl + mouse wheel` Adjust font size. - `ctrl + up` `ctrl + down` Move selected lines
- `ctrl + shift + mouse wheel` Adjust ui font size. - `ctrl + /` Toggle line comments
- `ctrl + up` & `ctrl + down` Move selected lines. - `ctrl + M` Toggle file meta info
- `ctrl + /` Toggle line comments.
- `ctrl + M` Toggle file meta info.
- `ctrl + F` Search for text in all files.
- `ctrl + shift + 0-9` Create hotkey for selected file.
- `ctrl + 0-9` Load hotkeyed file.
## Symbol View
- `ctrl + click` Select entire block + children.
- `ctrl + shift + click` Select block without children.
## Editor View
- `ctrl + click` anywhere: Scroll to nearest symbol in symbol view.
- `ctrl + click` inside brackets: Goto local file.
- `ctrl + shift +`
- `U` Make selection uppercase.
- `L` Make selection lowercase.
- `O` Make selection capitalized.
- `P` Make selection variable: `My text -> my_text`
# Symbols and Tags # Symbols and Tags
*Symbols* are like *Table of Contents* for a file. To make it easier to find stuff there is a *Symbol* viewer.
- `Markdown` uses headings `# Heading` - `Markdown` uses headings `# Heading`
- `JSON` uses Dictionaries `"object": {` - `JSON` uses Dictionaries `"object": {`
- `YAML` uses Dictionaries `object: ` - `YAML` uses Dictionaries `object: `
- `ini` `cfg` use headings `[heading]` - `ini` `cfg` use headings `[heading]`
Symbols can have *Tags*. Tags are added with comments. Symbols can have tags. Tags are added with comments.
- `Markdown` uses `<!-- #tag1 #tag2 -->` - `Markdown` uses `<!-- #tag1 #tag2 -->`
- `JSON` uses `"#": "#tag1 #tag2"` - `JSON` uses `"#": "#tag1 #tag2"`
@ -71,83 +57,9 @@ Click them to toggle on and off.\
This will then highlight *Files* and *Symbols* that have that tag. This will then highlight *Files* and *Symbols* that have that tag.
# Todo # Todo
- [x] `1.1` Preserve folders open/close state. - [ ] Preserve which folders are open/closed.
- [x] `1.3` Search all files. - [ ] Search
- [x] `1.7` Search file. - [ ] Find and replace
- [ ] Find and replace. - [ ] Meta data based on format.
- [x] `1.7` Improve meta data based on format. - [ ] Recycle folder
- [x] `1.2` Recycle folders. - [ ] Undo recycle
- [x] `1.2` Unrecylce. (Toggle `view/directories/.trash` and press green arrow.)
- [ ] JSON formatting.
- [ ] JSON error testing.
- [ ] Color themes.
# Mini features
## File List
### Colorize Folder
You can colorize files in a folder for easier identification. Right click a folder and select a color.
The `tab colors` toggle at the top will toggle tabs colorized by folder.
### Content Preview
You can preview the contents of a file by `ctrl + click`ing it.
The list is clickable, so you can go straight to a section of the file.
When using the filter, contents will be scanned.
## Content List (Symbols)
### Selecting Sections
`ctrl + click`ing on a symbol will select all lines contained in it, and it's childrens.
`ctrl + shift + click` a symbol will only select it's lines, not it's childrens.
## File Editor
### Follow Link
You can follow Markdown links by `ctrl + click`ing on them.
## Tags
The tag list displays all tags throughout the files.
To add a tag to a file, include a comment, with a hashtag:
- `.md`: `<!-- #tag1 #tag2 -->`
- `.json`: `{ "#": "#tag1 #tag2 }`
- `.ini` `.cfg`: `; #tag1 #tag2`
- `.yaml`: `# #tag1 #tag2`
`click` a tag to select it.
All files in the File List and symbols in the Symbol List containing the tag, will be highlighted.
`ctrl + click` to select multiple tags at once.
## Meta Panel
Toggle the meta panel with `ctrl + M`.
### Meta
The meta tab updates whenever you make a save.
It lists some information on the contents of your file.
Currently it mostly only works for Markdown.
### Search
todo
### System
Hitting refrsh will list all files in a table with sortable columns.
Select a column to sort on:
- Chapter count.
- Word count.
- Unique words.
- Progress.
- Time since modified.
### Image
In Markdown files (`.md`) you can `ctrl + click` an image to preview it.
Images look like: `![](image_url.png)` in Markdown.
# Icon credit
<a href="https://www.flaticon.com/free-icons/files-and-folders" title="files and folders icons">Files and folders icons created by Uniconlabs - Flaticon</a>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 121 KiB

1
addons/test.txt Normal file
View File

@ -0,0 +1 @@

View File

@ -1,17 +0,0 @@
tool
extends "res://addons/text_editor/TE_RichTextLabel.gd"
func _ready():
clear()
func msg(msg):
append_bbcode(str(msg))
newline()
func err(err):
append_bbcode(clr(err, Color.tomato))
newline()
func info(info):
append_bbcode(clr(info, Color.aquamarine))
newline()

View File

@ -1,27 +1,16 @@
tool tool
extends RichTextLabel extends RichTextLabel
var editor:TE_Editor var editor:TextEditor
var click_pos:Vector2
func _init(text):
set_bbcode(text)
visible = false
func _ready(): func _ready():
add_font_override("normal_font", editor.FONT_R) add_font_override("normal_font", editor.FONT_R)
click_pos = get_global_mouse_position() add_font_override("bold_font", editor.FONT_B)
# add_font_override("bold_font", editor.FONT_B) add_font_override("italics_font", editor.FONT_I)
# add_font_override("italics_font", editor.FONT_I) add_font_override("bold_italics_font", editor.FONT_BI)
# add_font_override("bold_italics_font", editor.FONT_BI)
rect_size = editor.FONT_R.get_string_size(text)
rect_size += Vector2(16, 16)
func _process(_delta): func _process(_delta):
var mp = get_global_mouse_position() set_global_position(get_global_mouse_position())
set_visible(mp.distance_to(click_pos) > 16.0)
set_global_position(mp + Vector2(16, 8))
func _input(e): func _input(e):
if e is InputEventMouseButton: if e is InputEventMouseButton:

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
tool tool
extends TextEdit extends TextEdit
var editor:TE_Editor var editor:TextEditor
var _hscroll:HScrollBar var _hscroll:HScrollBar
var _vscroll:VScrollBar var _vscroll:VScrollBar
@ -9,7 +9,6 @@ var helper:TE_ExtensionHelper
var temporary:bool = false setget set_temporary var temporary:bool = false setget set_temporary
var modified:bool = false var modified:bool = false
var file_path:String = "" var file_path:String = ""
var mouse_inside:bool = false
var symbols:Dictionary = {} var symbols:Dictionary = {}
var tags:Dictionary = {} var tags:Dictionary = {}
@ -18,130 +17,30 @@ var last_shift:bool
var last_selected:bool var last_selected:bool
var last_selection:Array = [0, 0, 0, 0] var last_selection:Array = [0, 0, 0, 0]
var color:String = ""
var hscroll:int = 0 var hscroll:int = 0
var vscroll:int = 0 var vscroll:int = 0
var in_focus:bool = false var in_focus:bool = false
func _ready(): func _ready():
# prefab?
if name == "file_editor":
set_process(false)
set_process_input(false)
return
var _e var _e
if not editor: if not editor:
editor = owner editor = owner
_e = editor.connect("save_files", self, "save_file") _e = editor.connect("save_files", self, "save_file")
_e = editor.connect("file_selected", self, "_file_selected") _e = editor.connect("file_selected", self, "_file_selected")
_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 = connect("text_changed", self, "text_changed") _e = connect("text_changed", self, "text_changed")
_e = connect("focus_entered", self, "_focus_entered") _e = connect("focus_entered", self, "set", ["in_focus", true])
_e = connect("focus_exited", self, "_focus_exited") _e = connect("focus_exited", self, "set", ["in_focus", false])
_e = connect("mouse_entered", self, "set", ["mouse_inside", true])
_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() get_menu().add_font_override("font", editor.FONT)
popup.add_font_override("font", editor.FONT)
popup.add_separator()
popup.add_item("Uppercase", 1000)
# var sc = ShortCut.new()
# sc.shortcut = InputEventKey.new()
# sc.shortcut.shift = true
# sc.shortcut.control = true
# sc.shortcut.scancode = KEY_U
# popup.add_item_shortcut(sc, 1000)
popup.add_item("Lowercase")
popup.add_item("Capitalize")
popup.add_item("Variable")
# popup.add_shortcut()
_e = popup.connect("index_pressed", self, "_popup_menu")
# hint
theme = Theme.new()
theme.set_font("font", "TooltipLabel", editor.FONT_R)
# var sb = StyleBoxFlat.new()
# sb.bg_color.a = .75
# theme.set_color("font_color", "TooltipLabel", Color(0,0,0,.5))
# theme.set_stylebox("panel", "TooltipPanel", sb)
# print(theme.get_color_list("TooltipLabel"))
# print(theme.get_color_types())
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):
if file_path.get_base_dir() == dir:
update_name()
func _popup_menu(index:int):
match get_menu().get_item_text(index):
"Uppercase": selection_uppercase()
"Lowercase": selection_lowercase()
"Capitalize": selection_capitalize()
"Variable": selection_variable()
func selection_uppercase():
var s = get_cursor_state()
insert_text_at_cursor(get_selection_text().to_upper())
set_cursor_state(s)
func selection_lowercase():
var s = get_cursor_state()
insert_text_at_cursor(get_selection_text().to_lower())
set_cursor_state(s)
func selection_variable():
var s = get_cursor_state()
insert_text_at_cursor(TE_Util.to_var(get_selection_text()))
set_cursor_state(s)
func selection_capitalize():
var s = get_cursor_state()
insert_text_at_cursor(get_selection_text().capitalize())
set_cursor_state(s)
func _node(n): func _node(n):
var _e var _e
if n is HScrollBar: if n is HScrollBar:
@ -157,108 +56,61 @@ 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 = { return {
hscroll=scroll_horizontal, hscroll=scroll_horizontal,
vscroll=scroll_vertical, vscroll=scroll_vertical
cursor=get_cursor_state()
} }
# unsaved
if file_path == "":
state.text = text
return state
func set_state(state:Dictionary): func set_state(state:Dictionary):
yield(get_tree(), "idle_frame") yield(get_tree(), "idle_frame")
if "hscroll" in state:
hscroll = state.hscroll hscroll = state.hscroll
vscroll = state.vscroll vscroll = state.vscroll
set_h_scroll(state.hscroll) set_h_scroll(state.hscroll)
set_v_scroll(state.vscroll) set_v_scroll(state.vscroll)
if "text" in state: func _file_renamed(old_path:String, new_path:String):
if state.text.strip_edges(): if old_path == file_path:
text = state.text file_path = new_path
else: update_name()
editor._close_file(file_path)
if "cursor" in state:
set_cursor_state(state.cursor)
func _update_selected_line():
var l = cursor_get_line()
editor.select_symbol_line(0)
for i in len(symbols):
var sindex = clamp(i, 0, len(symbols))
var symbol = symbols.values()[sindex]
if i == len(symbols)-1 or symbols.keys()[i+1] > l:
editor.select_symbol_line(sindex)
break
func get_line_symbols(line:int) -> PoolStringArray:
var depth:PoolStringArray = PoolStringArray()
for i in len(symbols):
var sindex = clamp(i, 0, len(symbols))
var symbol = symbols.values()[sindex]
while len(depth) <= symbol.deep:
depth.append("")
depth[symbol.deep] = symbol.name
if i == len(symbols)-1 or symbols.keys()[i+1] > line:
depth.resize(symbol.deep+1)
break
return depth
func _input(e): func _input(e):
if not editor.is_plugin_active(): if not editor.is_plugin_active():
return return
# custom tab system if not visible or not in_focus:
if visible and in_focus and e is InputEventKey and e.pressed and e.scancode == KEY_TAB:
if is_selection_active():
var a = get_selection_from_line()
var b = get_selection_to_line()
var lines = get_selection_text().split("\n")
if e.shift:
for i in len(lines):
lines[i] = lines[i].trim_prefix(helper.get_tab())
else:
for i in len(lines):
lines[i] = helper.get_tab() + lines[i]
insert_text_at_cursor(lines.join("\n"))
select(a, 0, b, len(get_line(b)))
else:
insert_text_at_cursor(helper.get_tab())
get_tree().set_input_as_handled()
if not visible or not in_focus or not mouse_inside:
return return
# show current position in heirarchy as editor hint if e is InputEventKey and e.pressed and e.control:
if e is InputEventMouseButton and not e.pressed: # tab to next
_update_selected_line() if e.scancode == KEY_TAB:
get_tree().set_input_as_handled()
if e.shift:
get_parent().prev()
else:
get_parent().next()
if e is InputEventMouseButton and not e.pressed and e.control: # save files
var line:String = get_line(cursor_get_line()) elif e.scancode == KEY_S:
get_tree().set_input_as_handled()
editor.save_files()
# click link # close file
var ca = line.find("(") elif e.scancode == KEY_W:
var cb = line.find_last(")") get_tree().set_input_as_handled()
if ca != -1 and cb != -1: if e.shift:
var a:int = cursor_get_column() editor.open_last_file()
var b:int = cursor_get_column() else:
if ca < a and cb >= b: close()
while a > 0 and not line[a] in "(": a -= 1
while b <= len(line) and not line[b] in ")": b += 1
var file = line.substr(a+1, b-a-1)
var link = file_path.get_base_dir().plus_file(file)
editor.open_file(link)
editor.select_file(link)
# remember last selection # remember last selection
if e is InputEventKey and e.pressed: if e is InputEventKey and e.pressed:
@ -301,30 +153,6 @@ func _input(e):
select(f+1, 0, t+1, len(get_line(t+1))) select(f+1, 0, t+1, len(get_line(t+1)))
cursor_set_line(cursor_get_line()+1, false) cursor_set_line(cursor_get_line()+1, false)
if e.scancode == KEY_U:
if get_selection_text() == get_selection_text().to_upper():
selection_lowercase()
else:
selection_uppercase()
if e.scancode == KEY_L:
if get_selection_text() == get_selection_text().to_lower():
selection_uppercase()
else:
selection_lowercase()
if e.scancode == KEY_O:
if get_selection_text() == get_selection_text().capitalize():
selection_variable()
else:
selection_capitalize()
if e.scancode == KEY_P:
if get_selection_text() == TE_Util.to_var(get_selection_text()):
selection_capitalize()
else:
selection_variable()
func _unhandled_key_input(e): func _unhandled_key_input(e):
if not visible: if not visible:
return return
@ -334,36 +162,16 @@ 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 p != file_path: if not p:
return return
if p == file_path:
grab_focus()
grab_click_focus()
update_symbols() update_symbols()
update_heading() update_heading()
# yield(get_tree(), "idle_frame")
#
# grab_focus()
# grab_click_focus()
func goto_symbol(index:int):
var syms = symbols.keys()
if syms and index >= 0 and index < len(syms):
goto_line(syms[index])
func goto_line(line:int, bottom:bool=true):
# force scroll to bottom so selected line will be at top
if bottom:
cursor_set_line(get_line_count())
cursor_set_line(line)
_update_selected_line()
func text_changed(): func text_changed():
if last_selected: if last_selected:
match last_key: match last_key:
@ -381,7 +189,7 @@ func text_changed():
insert_text_at_cursor("`%s`" % get_selection_text()) insert_text_at_cursor("`%s`" % get_selection_text())
_: _:
pass print(last_key)
if not modified: if not modified:
if temporary: if temporary:
@ -394,8 +202,6 @@ func set_temporary(t):
update_name() update_name()
func update_symbols(): func update_symbols():
update_helper()
symbols.clear() symbols.clear()
tags.clear() tags.clear()
@ -411,61 +217,41 @@ func update_symbols():
else: else:
tags[tag] += 1 tags[tag] += 1
# var _e = TE_Util.sort(tags, true)
editor._file_symbols_updated(file_path) editor._file_symbols_updated(file_path)
func close(): func close():
if modified: if modified:
if not editor.popup_unsaved.visible:
var _e var _e
_e = editor.popup_unsaved.connect("confirmed", self, "_popup", ["confirm_close"], CONNECT_ONESHOT) _e = editor.popup_unsaved.connect("confirmed", self, "_popup", ["close"], CONNECT_ONESHOT)
_e = editor.popup_unsaved.connect("custom_action", self, "_popup", [], CONNECT_ONESHOT) _e = editor.popup_unsaved.connect("custom_action", self, "_popup", [], CONNECT_ONESHOT)
# _e = editor.popup_unsaved.connect("hide", self, "_popup", ["cancel"], CONNECT_ONESHOT)
editor.popup_unsaved.show() editor.popup_unsaved.show()
else: else:
editor._close_file(file_path) editor._close_file(file_path)
func _popup(msg): func _popup(msg):
match msg: match msg:
"confirm_close": "close":
editor._close_file(file_path) editor._close_file(file_path)
"save_and_close": "save_and_close":
save_file() save_file()
editor._close_file(file_path) editor._close_file(file_path)
editor.popup_unsaved.disconnect("confirmed", self, "_popup")
editor.popup_unsaved.disconnect("custom_action", self, "_popup")
func load_file(path:String): func load_file(path:String):
file_path = path file_path = path
if path != "": text = TE_Util.load_text(path)
text = editor.load_file(path)
clear_undo_history()
update_colors()
update_name() update_name()
func update_helper(): # update colors
helper = editor.get_extension_helper(file_path) clear_colors()
helper = TextEditor.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):
file_path = fp
modified = false
update_name()
update_symbols()
func save_file(): func save_file():
if file_path == "" and text:
editor.popup_create_file(editor.current_directory, text, funcref(self, "_created_nonexisting"))
else:
if modified: if modified:
if not file_path.begins_with(editor.current_directory): if not file_path.begins_with("res://"):
var err_msg = "can't save to %s" % file_path push_error("can't save to %s" % file_path)
push_error(err_msg)
editor.console.err(err_msg)
return return
modified = false modified = false
@ -474,35 +260,12 @@ func save_file():
update_symbols() update_symbols()
func update_name(): func update_name():
var n:String var n = file_path.get_file().split(".", true, 1)[0]
if file_path == "":
n = "UNSAVED"
else:
n = file_path.get_file().split(".", true, 1)[0]
if editor.ignore_head_numbers:
n = editor._split_header(n)[1]
if temporary: n = "?" + n if temporary: n = "?" + n
if modified: n = "*" + n if modified: n = "*" + n
if len(n) > 12:
n = n.substr(0, 9) + "..."
if editor.show_tab_color:
var color = editor.get_file_tint_name(file_path)
var path = "res://addons/text_editor/icons/icon_%s.png" % color
if File.new().file_exists(path):
editor.tab_parent.set_tab_icon(get_index(), load(path))
else:
editor.tab_parent.set_tab_icon(get_index(), null)
else:
editor.tab_parent.set_tab_icon(get_index(), null)
editor.tab_parent.set_tab_title(get_index(), n) editor.tab_parent.set_tab_title(get_index(), n)
name = n update_heading()
func update_heading(): func update_heading():
if Engine.editor_hint: if Engine.editor_hint:
@ -519,5 +282,5 @@ func update_heading():
OS.set_window_title("%s - Text Editor" % f) OS.set_window_title("%s - Text Editor" % f)
func needs_save() -> bool: func needs_save() -> bool:
return modified or (not File.new().file_exists(file_path) and text) return modified or not File.new().file_exists(file_path)

View File

@ -1,101 +0,0 @@
tool
extends Node
const DIM:Color = Color.webgray
const CLR:Color = Color.white
onready var editor:TE_Editor = owner
var tab:TextEdit = null
var typed:String = ""
var word_count:int = 0
func _ready():
var _e
yield(get_tree(), "idle_frame")
_e = editor.tab_parent.connect("tab_changed", self, "_tab_changed")
editor.override_fonts($l)
editor.override_fonts($m)
editor.override_fonts($r)
func _tab_changed(index:int):
if tab and is_instance_valid(tab) and not tab.is_queued_for_deletion():
tab.disconnect("cursor_changed", self, "_cursor_changed")
tab = null
var new_tab = editor.tab_parent.get_child(index)
if tab == new_tab:
return
tab = new_tab
var _e
_e = tab.connect("cursor_changed", self, "_cursor_changed")
# _e = tab.connect("text_changed", self, "_text_changed")
#
#func _text_changed():
## print("text changed")
# pass
func _input(event):
if event is InputEventKey and event.pressed and tab and is_instance_valid(tab) and tab.has_focus():
if not event.scancode == KEY_BACKSPACE:
if char(event.scancode) in " .?!-":
word_count += 1
typed = ""
else:
typed += char(event.scancode)
_cursor_changed()
func _cursor_changed():
var l_lines:PoolStringArray = PoolStringArray()
var m_lines:PoolStringArray = PoolStringArray()
var r_lines:PoolStringArray = PoolStringArray()
var l:RichTextLabel
if tab.is_selection_active():
var seltext:String = tab.get_selection_text()
var words = {}
var word_count:int = TE_Util.count_words(seltext, words, null, false)
m_lines.append(kv("chars", len(seltext)))
m_lines.append(kv("words", word_count))
var l1 = tab.get_selection_from_line() + 1
var l2 = tab.get_selection_to_line() + 1
var c1 = tab.get_selection_from_column()
var c2 = tab.get_selection_to_column()
if l1 == l2:
l_lines.append(kv("line", l1))
l_lines.append(kv("char", "%s - %s" % [c1, c2]))
else:
l_lines.append(clr("line: ", DIM) + clr(str(l1), CLR) + clr(":", DIM) + clr(str(c1), CLR))
l_lines.append(clr("->", Color.webgray))
l_lines.append(clr("line: ", DIM) + clr(str(l2), CLR) + clr(":", DIM) + clr(str(c2), CLR))
m_lines.append(kv("lines", abs(l2 - l1) + 1))
else:
l_lines.append(kv("line", tab.cursor_get_line() + 1))
l_lines.append(kv("char", tab.cursor_get_column()))
var depth = tab.get_line_symbols(tab.cursor_get_line())
for i in len(depth):
depth[i] = b(depth[i])
r_lines.append(depth.join(clr("/", DIM)))
m_lines.append(kv("typed", word_count))
$l.set_bbcode(l_lines.join(" "))
$m.set_bbcode("[center]" + m_lines.join(" "))
$r.set_bbcode("[right]" +r_lines.join(" "))
func kv(k:String, v) -> String:
var clr2 = Color.white
if v is int:
v = TE_Util.commas(v)
return clr(k + ": ", DIM) + clr(str(v), clr2)
func b(t:String) -> String: return "[b]%s[/b]" % t
func i(t:String) -> String: return "[i]%s[/i]" % t
func u(t:String) -> String: return "[u]%s[/u]" % t
func clr(t:String, c:Color) -> String: return "[color=#%s]%s[/color]" % [c.to_html(), t]

View File

@ -1,82 +1,12 @@
extends TabContainer extends TabContainer
onready var editor:TE_Editor = owner onready var editor:TextEditor = owner
var mouse:bool = false var mouse:bool = false
var last_tab_index:int = -1
var tab_menu:PopupMenu
func _ready(): func _ready():
if not editor.is_plugin_active():
return
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")
_e = connect("pre_popup_pressed", self, "update_popup")
add_font_override("font", editor.FONT_R)
tab_menu = owner.get_node("popup_tab_menu")
tab_menu.connect("index_pressed", self, "_popup_selected")
func _tab_changed(index):
var tab = get_child(index)
tab.grab_focus()
last_tab_index = index
func _popup_selected(index:int):
var tindex := tab_menu.get_item_id(index)
if tindex >= 100:
current_tab = tindex - 100
return
match tindex:
0: # close
get_child(hovered_tab_index).close()
1: # close others
var all_tabs = owner.get_tabs()
var hovered = get_child(hovered_tab_index)
for tab in all_tabs:
if tab != hovered:
tab.close()
2: # close left
var all_tabs = owner.get_tabs()
for i in range(0, hovered_tab_index):
all_tabs[i].close()
current_tab = 0
3: # close right
var all_tabs = owner.get_tabs()
for i in range(hovered_tab_index+1, len(all_tabs)):
all_tabs[i].close()
var hovered_tab_index:int
func update_popup(index:int=current_tab):
var all_tabs = owner.get_tabs()
hovered_tab_index = index
tab_menu.clear()
tab_menu.rect_size = Vector2.ZERO
tab_menu.add_item("Close", 0)
tab_menu.add_item("Close others", 1)
if index > 0:
tab_menu.add_item("Close all to left", 2)
if index < len(all_tabs)-1:
tab_menu.add_item("Close all to right", 3)
tab_menu.add_separator()
var i = 0
for tab in owner.get_tabs():
tab_menu.add_item(tab.name, 100+i)
i += 1
func _input(e): func _input(e):
if not editor.is_plugin_active(): if not editor.is_plugin_active():
@ -91,14 +21,6 @@ func _input(e):
next() next()
get_tree().set_input_as_handled() get_tree().set_input_as_handled()
elif e.button_index == BUTTON_RIGHT:
var index := get_tab_idx_at_point(get_local_mouse_position())
if index != -1:
update_popup(index)
tab_menu.rect_global_position = get_global_mouse_position()
tab_menu.popup()
get_tree().set_input_as_handled()
if e is InputEventKey and e.pressed and e.control and e.scancode == KEY_TAB: if e is InputEventKey and e.pressed and e.control and e.scancode == KEY_TAB:
if e.shift: if e.shift:
prev() prev()

View File

@ -1,16 +1,18 @@
tool tool
extends "res://addons/text_editor/TE_RichTextLabel.gd" extends RichTextLabel
onready var editor:TextEditor = owner
onready var file_popup:PopupMenu = $file_popup onready var file_popup:PopupMenu = $file_popup
onready var dir_popup:PopupMenu = $dir_popup onready var dir_popup:PopupMenu = $dir_popup
const DragLabel = preload("res://addons/text_editor/TE_DragLabel.gd") const DragLabel = preload("res://addons/text_editor/TE_DragLabel.gd")
var drag_label:RichTextLabel var drag_label:RichTextLabel
export var p_filter:NodePath var files:Array = []
var filter:String = "" var dirs:Array = []
var selected:Array = [] var selected
var dragging:Array = [] var hovered:String = ""
var dragging:String = ""
var drag_start:Vector2 var drag_start:Vector2
func _ready(): func _ready():
@ -21,10 +23,12 @@ func _ready():
_e = editor.connect("file_closed", self, "_file_closed") _e = editor.connect("file_closed", self, "_file_closed")
_e = editor.connect("file_selected", self, "_file_selected") _e = editor.connect("file_selected", self, "_file_selected")
_e = editor.connect("file_renamed", self, "_file_renamed") _e = editor.connect("file_renamed", self, "_file_renamed")
_e = connect("meta_hover_started", self, "_meta_entered")
_e = connect("meta_hover_ended", self, "_meta_exited")
var le:LineEdit = get_node(p_filter) # hint
_e = le.connect("text_changed", self, "_filter_changed") theme = Theme.new()
le.add_font_override("font", editor.FONT_R) theme.set_font("font", "TooltipLabel", editor.FONT_R)
# file popup # file popup
file_popup.clear() file_popup.clear()
@ -33,71 +37,34 @@ func _ready():
file_popup.add_separator() file_popup.add_separator()
file_popup.add_item("Remove") file_popup.add_item("Remove")
_e = file_popup.connect("index_pressed", self, "_file_popup") _e = file_popup.connect("index_pressed", self, "_file_popup")
file_popup.add_font_override("font", editor.FONT) file_popup.add_font_override("font", TextEditor.FONT)
# dir popup # dir popup
dir_popup.clear() dir_popup.clear()
dir_popup.rect_size = Vector2.ZERO dir_popup.rect_size = Vector2.ZERO
dir_popup.add_item("New File") dir_popup.add_item("New File")
dir_popup.add_separator() dir_popup.add_item("New Folder")
dir_popup.add_item("Remove")
dir_popup.add_separator()
dir_popup.add_item("Tint Yellow")
dir_popup.add_item("Tint Red")
dir_popup.add_item("Tint Blue")
dir_popup.add_item("Tint Green")
dir_popup.add_item("Reset Tint")
_e = dir_popup.connect("index_pressed", self, "_dir_popup") _e = dir_popup.connect("index_pressed", self, "_dir_popup")
dir_popup.add_font_override("font", editor.FONT) dir_popup.add_font_override("font", TextEditor.FONT)
add_font_override("normal_font", editor.FONT_R) add_font_override("normal_font", editor.FONT_R)
add_font_override("bold_font", editor.FONT_B) add_font_override("bold_font", editor.FONT_B)
add_font_override("italics_font", editor.FONT_I) add_font_override("italics_font", editor.FONT_I)
add_font_override("bold_italics_font", editor.FONT_BI) add_font_override("bold_italics_font", editor.FONT_BI)
func _filter_changed(t:String):
filter = t
_redraw()
func _dir_popup(index:int): func _dir_popup(index:int):
var type = selected[0] var p = _meta_to_file(selected)
var file = selected[1] var type = p[0]
if type == "d": var file = p[1]
file = file.file_path
match dir_popup.get_item_text(index): match dir_popup.get_item_text(index):
"New File": "New File": editor.popup_create_file(file)
editor.popup_create_file(file) "New Folder": editor.popup_create_dir(file)
"Remove":
editor.recycle(file, type == "f")
"Tint Yellow":
selected[1].tint = "yellow"#Color.gold
editor.emit_signal("dir_tint_changed", selected[1].file_path)
_redraw()
"Tint Red":
selected[1].tint = "red"#Color.tomato
editor.emit_signal("dir_tint_changed", selected[1].file_path)
_redraw()
"Tint Blue":
selected[1].tint = "blue"#Color.deepskyblue
editor.emit_signal("dir_tint_changed", selected[1].file_path)
_redraw()
"Tint Green":
selected[1].tint = "green"#Color.chartreuse
editor.emit_signal("dir_tint_changed", selected[1].file_path)
_redraw()
"Reset Tint":
selected[1].tint = ""#Color.white
editor.emit_signal("dir_tint_changed", selected[1].file_path)
_redraw()
func _file_popup(index:int): func _file_popup(index:int):
var type = selected[0] var p = _meta_to_file(selected)
var file = selected[1] var type = p[0]
if type == "d": var file = p[1]
file = file.file_path
match file_popup.get_item_text(index): match file_popup.get_item_text(index):
"Rename": "Rename":
@ -108,98 +75,70 @@ func _file_popup(index:int):
"Remove": "Remove":
if type == "f": if type == "f":
editor.recycle(file, true) editor.recycle_file(file)
_: _:
selected = [] selected = {}
func _renamed(new_file:String): func _renamed(new_file:String):
var type = selected[0] var p = _meta_to_file(selected)
var file = selected[1] var type = p[0]
var file = p[1]
var old_path:String = file var old_path:String = file
var old_file:String = old_path.get_file() var old_file:String = old_path.get_file()
if new_file != old_file: if new_file != old_file:
var new_path:String = old_path.get_base_dir().plus_file(new_file) var new_path:String = old_path.get_base_dir().plus_file(new_file)
editor.rename_file(old_path, new_path) editor.rename_file(old_path, new_path)
selected = [] selected = {}
func _input(e:InputEvent): func _input(e:InputEvent):
if not editor.is_plugin_active(): if not editor.is_plugin_active():
return return
if e is InputEventMouseButton and meta_hovered: if e is InputEventMouseButton and hovered:
var type = meta_hovered[0] var p = _meta_to_file(hovered)
var file = meta_hovered[1] var type = p[0]
var file = p[1]
if e.button_index == BUTTON_LEFT: if e.button_index == BUTTON_LEFT:
if e.pressed: if e.pressed:
if type in ["f", "d"]: dragging = hovered
if type == "f" and Input.is_key_pressed(KEY_CONTROL): if type == "f":
editor.file_data[file].open = not editor.file_data[file].open drag_label = DragLabel.new()
_redraw()
else:
var file_path = file if type == "f" else file.file_path
# can't move recycling
if editor.is_trash_path(file_path):
return
# select for drag
else:
dragging = meta_hovered
drag_label = DragLabel.new(file_path.get_file())
drag_label.editor = editor drag_label.editor = editor
drag_label.set_bbcode(file.get_file())
editor.add_child(drag_label) editor.add_child(drag_label)
else: else:
if type == "f" and Input.is_key_pressed(KEY_CONTROL): if dragging and dragging != hovered:
pass var p2 = _meta_to_file(dragging)
var drag_type = p[0]
else: var drag_file = p[1]
if dragging and dragging != meta_hovered: if drag_type == "f" and type == "d":
var drag_type = dragging[0] var dir:String = file
var drag_file = dragging[1] var old_path:String = drag_file
# dragged onto directory?
if type == "d":
var dir:String = file.file_path
var old_path:String = drag_file if drag_type == "f" else drag_file.file_path
var new_path:String = dir.plus_file(old_path.get_file()) var new_path:String = dir.plus_file(old_path.get_file())
editor.rename_file(old_path, new_path) editor.rename_file(old_path, new_path)
dragging = []
else: else:
match type: match type:
# toggle directory # toggle directory
"d": "d":
file.open = not file.open p[2].open = not p[2].open
_redraw() _redraw()
# unrecycle
"unrecycle":
editor.unrecycle(file.file_path)
# select # select
"f": "f":
editor.select_file(file) editor.select_file(file)
# select file symbol
"fs":
editor.select_file(file)
var tab = editor.get_selected_tab()
yield(get_tree(), "idle_frame")
tab.goto_symbol(meta_hovered[2])
get_tree().set_input_as_handled() get_tree().set_input_as_handled()
elif e.button_index == BUTTON_RIGHT: elif e.button_index == BUTTON_RIGHT:
if e.pressed: if e.pressed:
selected = meta_hovered selected = hovered
match type: match type:
"d": "d":
dir_popup.set_global_position(get_global_mouse_position()) dir_popup.set_global_position(get_global_mouse_position())
@ -210,6 +149,26 @@ func _input(e:InputEvent):
file_popup.popup() file_popup.popup()
get_tree().set_input_as_handled() get_tree().set_input_as_handled()
func _meta_to_file(m:String):
var p = m.split(":", true, 1)
var type = p[0]
var index = int(p[1])
match type:
"d":
return [type, dirs[index].file_path, dirs[index]]
"f":
return [type, files[index]]
func _meta_entered(m):
hovered = m
var f = _meta_to_file(m)
match f[0]:
"f", "d": hint_tooltip = f[1]
func _meta_exited(_m):
hovered = ""
hint_tooltip = ""
func _file_opened(_file_path:String): _redraw() func _file_opened(_file_path:String): _redraw()
func _file_closed(_file_path:String): _redraw() func _file_closed(_file_path:String): _redraw()
func _file_selected(_file_path:String): _redraw() func _file_selected(_file_path:String): _redraw()
@ -219,139 +178,76 @@ var lines:PoolStringArray = PoolStringArray()
func _redraw(): func _redraw():
lines = PoolStringArray() lines = PoolStringArray()
lines.append_array(_draw_dir(editor.file_list[""], 0)) dirs.clear()
files.clear()
_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 clr(s:String, c:Color) -> String: return "[color=#%s]%s[/color]" % [c.to_html(), s]
var on = false func i(s:String) -> String: return "[i]%s[/i]" % s
var parts = [] func b(s:String) -> String: return "[b]%s[/b]" % s
for c in s: func url(s:String, url:String) -> String: return "[url=%s]%s[/url]" % [url, s]
on = c in "0123456789_-"
if not parts or parts[-1][0] != on:
parts.append([on, ""])
parts[-1][1] += c
var out = ""
for p in parts:
out += clr(p[1], dull if p[0] else clr)
return out
const FOLDER_CLOSED:String = "🗀" # not visible in Godot. const FOLDER:String = "🗀" # not visible in godot
const FOLDER_OPEN:String = "🗁" # not visible in Godot. func _draw_dir(dir:Dictionary, deep:int):
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 dull = Color.white.darkened(.65)
var dull_tint = tint.darkened(.5)
var space = "" var space = clr("".repeat(deep), Color.white.darkened(.8))
var file:String = dir.file_path var file:String = dir.file_path
var name:String = b(file.get_file())
space = clr("".repeat(deep), Color.white.darkened(.8))
var head:String = "" if dir.open else "" var head:String = "" if dir.open else ""
var fold:String = FOLDER_OPEN if dir.open else FOLDER_CLOSED var dir_index:int = len(dirs)
var dname = b(_dull_nonwords(file.get_file(), tint.darkened(0 if editor.is_dir_tagged(dir) else 0.5), dull)) var link:String = url(space+clr(FOLDER+head, Color.white.darkened(.5))+" "+name, "d:%s" % dir_index)
dname = clr("", dull) + dname + clr("", dull) lines.append(clr(link, Color.white.darkened(dimmest)))
head = clr(space+fold, Color.gold) + clr(head, Color.white.darkened(.5)) dirs.append(dir)
head += " %s" % dname
var link:String = meta(head, ["d", dir], editor.get_localized_path(file))
if editor.is_trash_path(file):
link += " " + meta(clr("", Color.yellowgreen), ["unrecycle", dir], file)
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 or filter: if dir.open:
# 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 or filter): if file_path is Dictionary:
out.append_array(_draw_dir(file_path, deep+1)) _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]
var fname = file_path.get_file() file = file_path.get_file()
file = fname var p = 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]
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 = Color.white
head = "" if filter else "┣╸" if i != last else "┗╸" head = "┣╸" if i != last else "┗╸"
var fname_lower = fname.to_lower() if "readme" in file.to_lower():
if "readme" in fname_lower:
head = "🛈" head = "🛈"
if is_selected:
head = ""
elif is_opened:
head = ""
head = clr(head, Color.white.darkened(.5 if is_opened else .75)) head = clr(head, Color.white.darkened(.5 if is_opened else .75))
var bold = false
if is_tagging: if is_tagging:
if editor.is_tagged(file_path): if editor.is_tagged(file_path):
bold = true file = b(file)
else: else:
color = color.darkened(dimmest) color = color.darkened(dimmest)
else: else:
pass pass
file = _dull_nonwords(file, color, dull) file = clr(file, color)
ext = clr("." + ext, Color.white.darkened(.65))
if bold: var line = space + head + file + ext
file = b(file) lines.append(url(line, "f:%s" % len(files)))
files.append(file_path)
ext = "" if not ext else clr("." + ext, dull)
var line = file + ext
if is_selected:
line = u(line)
var hint_path = editor.get_localized_path(file_path)
var file_lines = []
if not editor._scanning:
var fdata = editor.get_file_data(file_path)
var symbols = fdata.symbols.values()
for j in range(1, len(symbols)):
if fdata.open or filter:
var sdata:Dictionary = symbols[j]
var sname:String = sdata.name
var index = sname.to_lower().find(filter)
if filter and index == -1:
continue
var sname_highlighted = TE_Util.highlight(sname, index, len(filter), TE_Util.hue_shift(dull_tint, -.075), Color.white)
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 filter:
var index = fname_lower.find(filter)
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

View File

@ -1,7 +1,7 @@
tool tool
extends LineEdit extends LineEdit
onready var editor:TE_Editor = owner onready var editor:TextEditor = owner
var fr:FuncRef var fr:FuncRef
func _ready(): func _ready():
@ -9,20 +9,16 @@ func _ready():
_e = connect("text_entered", self, "_enter") _e = connect("text_entered", self, "_enter")
_e = connect("focus_exited", self, "_lost_focus") _e = connect("focus_exited", self, "_lost_focus")
add_font_override("font", editor.FONT_R) add_font_override("font", TextEditor.FONT_R)
func _unhandled_key_input(e): func _unhandled_key_input(e):
if not editor.is_plugin_active(): if e.scancode == KEY_ESCAPE and e.pressed:
return
if visible and e.scancode == KEY_ESCAPE and e.pressed:
fr = null fr = null
hide() hide()
get_tree().set_input_as_handled() get_tree().set_input_as_handled()
func display(t:String, obj:Object, fname:String): func display(t:String, obj:Object, fname:String):
text = t text = t
select_all()
fr = funcref(obj, fname) fr = funcref(obj, fname)
show() show()
call_deferred("grab_focus") call_deferred("grab_focus")
@ -32,6 +28,5 @@ func _lost_focus():
hide() hide()
func _enter(t:String): func _enter(t:String):
if fr:
fr.call_func(t) fr.call_func(t)
hide() hide()

View File

@ -1,13 +1,16 @@
tool tool
extends "res://addons/text_editor/TE_RichTextLabel.gd" extends TE_RichTextLabel
onready var editor:TextEditor = owner
func _ready(): func _ready():
var _e var _e
_e = editor.connect("file_selected", self, "_file_selected") _e = editor.connect("file_selected", self, "_file_selected")
_e = editor.connect("file_saved", self, "_file_saved") _e = editor.connect("file_saved", self, "_file_saved")
#func _resized(): func _unhandled_key_input(e):
# add_constant_override("table_hseparation", int(rect_size.x / 6.0)) if e.scancode == KEY_M and e.pressed:
visible = not visible
func _file_selected(_file_path:String): func _file_selected(_file_path:String):
yield(get_tree(), "idle_frame") yield(get_tree(), "idle_frame")
@ -17,9 +20,6 @@ func _file_saved(_file_path:String):
_redraw() _redraw()
func _redraw(): func _redraw():
if not visible:
return
var tab = editor.get_selected_tab() var tab = editor.get_selected_tab()
if tab: if tab:
tab.helper.generate_meta(tab, self) tab.helper.generate_meta(tab, self)

View File

@ -1,39 +0,0 @@
tool
extends TabContainer
onready var editor:TE_Editor = owner
func _ready():
if not editor.is_plugin_active():
return
set_visible(false)
add_font_override("font", editor.FONT_R)
func _unhandled_key_input(e):
if not editor.is_plugin_active():
return
if e.control and e.pressed:
match e.scancode:
# show this menu
KEY_M:
set_visible(not get_parent().visible)
get_tree().set_input_as_handled()
# find menu
KEY_F:
set_visible(true)
select_tab($search)
$search/rte.select()
func set_visible(v:bool):
get_parent().visible = v
func select_tab(tab:Node):
current_tab = tab.get_index()
func show_image(file_path:String):
get_parent().visible = true
select_tab($image)
$image/image.texture = TE_Util.load_image(file_path)

View File

@ -1,88 +1,13 @@
extends RichTextLabel extends RichTextLabel
class_name TE_RichTextLabel
onready var editor:TE_Editor = owner
var meta_items:Array = []
var meta_hovered:Array = []
class Table:
var table_id:String
var heading:Array = []
var columns:Array = []
var _sort_index:int
var _sort_reverse:bool
func _init(id:String):
table_id = id
func sort(index:int, reverse:bool):
_sort_index = index
_sort_reverse = reverse
columns.sort_custom(self, "_sort")
func output(rte:RichTextLabel):
rte.push_table(len(heading))
for i in len(heading):
rte.push_cell()
rte.push_bold()
rte.push_meta("table|%s|%s" % [table_id, i])
rte.add_text(heading[i])
rte.pop()
rte.pop()
rte.pop()
for i in len(columns):
rte.push_cell()
rte.add_text(str(columns[i]))
rte.pop()
rte.pop()
class RTE:
var rte
var s:String
func start(st:String):
s = st
return self
func clr(c:Color):
s = "[color=#%s]%s[/color]" % [c.to_html(), s]
return self
func meta(type:String, meta, args=null):
var index:int = len(rte.meta_items)
rte.meta_items.append(meta)
s = "[url=%s|%s]%s[/url]" % [type, index, s]
return self
func out():
rte.append_bbcode(s)
func _ready(): func _ready():
# hint
theme = Theme.new()
theme.set_font("font", "TooltipLabel", editor.FONT_R)
add_font_override("normal_font", owner.FONT_R) add_font_override("normal_font", owner.FONT_R)
add_font_override("bold_font", owner.FONT_B) add_font_override("bold_font", owner.FONT_B)
add_font_override("italics_font", owner.FONT_I) add_font_override("italics_font", owner.FONT_I)
add_font_override("bold_italics_font", owner.FONT_BI) add_font_override("bold_italics_font", owner.FONT_BI)
var _e
_e = connect("resized", self, "_resized")
_e = connect("meta_clicked", self, "_meta_clicked")
_e = connect("meta_hover_started", self, "_meta_hover_started")
_e = connect("meta_hover_ended", self, "_meta_hover_ended")
func _resized():
pass
func _clicked(_data):
pass
func clear():
.clear()
meta_items.clear()
func table(rows) -> String: func table(rows) -> String:
var cells = "" var cells = ""
var clr = Color.white.darkened(.5).to_html() var clr = Color.white.darkened(.5).to_html()
@ -94,34 +19,3 @@ func table(rows) -> String:
for item in rows[i]: for item in rows[i]:
cells += "[cell][color=#%s]%s[/color][/cell]" % [clr, item] cells += "[cell][color=#%s]%s[/color][/cell]" % [clr, item]
return "[center][table=%s]%s[/table][/center]" % [len(rows[0]), cells] return "[center][table=%s]%s[/table][/center]" % [len(rows[0]), cells]
func b(t:String) -> String: return "[b]%s[/b]" % t
func i(t:String) -> String: return "[i]%s[/i]" % t
func u(t:String) -> String: return "[u]%s[/u]" % t
func clr(t:String, c:Color) -> String: return "[color=#%s]%s[/color]" % [c.to_html(), t]
func center(t:String): return "[center]%s[/center]" % t
func _meta_hover_started(meta):
var info = meta_items[int(meta)]
var hint = info[1]
meta_hovered = info[0]
if hint:
hint_tooltip = hint
func _meta_hover_ended(_meta):
meta_hovered = []
hint_tooltip = ""
func _meta_clicked(meta):
var info = meta_items[int(meta)]
if info[0]:
_clicked(info[0])
func add_meta(args:Array, hint:String) -> int:
var index:int = len(meta_items)
meta_items.append([args, hint])
return index
func meta(t:String, args:Array=[], hint:String="") -> String:
var index:int = add_meta(args, hint)
return "[url=%s]%s[/url]" % [index, t]

View File

@ -1,244 +0,0 @@
tool
extends "res://addons/text_editor/TE_RichTextLabel.gd"
var chapter_info:Array = []
var sort_on:String = "words"
var sort_on_index:int = 1
var sort_reverse:Dictionary = { id=true, chaps=true, words=true, uwords=true, "%":true, modified=true }
var skip_words:PoolStringArray
func _ready():
var btn = get_parent().get_node("update")
btn.add_font_override("font", editor.FONT_R)
var _e = btn.connect("pressed", self, "_update")
func _update():
chapter_info.clear()
# load block list
var skip_list = editor.current_directory.plus_file("word_skip_list.txt")
if File.new().file_exists(skip_list):
skip_words = TE_Util.load_text(skip_list).replace("\n", " ").strip_edges().to_lower().split(" ")
else:
skip_words = PoolStringArray()
for path in editor.file_paths:
var file = path.get_file()
var ext = file.get_extension()
match ext:
"md": _process_md(path)
# clear empty
for i in range(len(chapter_info)-1, -1, -1):
var info = chapter_info[i]
if not info.words:
chapter_info.remove(i)
_sort()
_redraw()
const WEEKDAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
const MONTHS = ["Januaray", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
const TIMES:Dictionary = {
"second": 60,
"minute": 60,
"hour": 24,
"day": INF
}
func get_time(t:int) -> String:
for k in TIMES:
if t < TIMES[k]:
return "%s %s ago" % [t, k + ("" if t == 1 else "s")]
t /= TIMES[k]
return "???"
func _process_md(path:String):
var lines = TE_Util.load_text(path).split("\n")
var file_time = File.new().get_modified_time(path)
var curr_time = OS.get_unix_time()
var diff_time = curr_time - file_time
var time_nice = get_time(diff_time)
if false and diff_time > 9999999:
time_nice = OS.get_datetime_from_unix_time(file_time)
time_nice.weekday = WEEKDAYS[time_nice.weekday-1].substr(0, 3).to_lower()
time_nice.month = MONTHS[time_nice.month-1].substr(0, 3).to_lower()
time_nice.hour12 = str(time_nice.hour % 12)
time_nice.ampm = "am" if time_nice.hour > 12 else "pm"
time_nice = "{weekday} {month} {day}, {year} {hour12}:{minute}:{second}{ampm}".format(time_nice)
var out = { path=path, line=0, id=editor.get_localized_path(path), modified=file_time, time_nice=time_nice, words=0, uwords={}, chaps=0, "%":0.0 }
chapter_info.append(out)
var i = 0
while i < len(lines):
# skip head meta
if i == 0 and lines[i].begins_with("---"):
i += 1
while i < len(lines) and not lines[i].begins_with("---"):
if ":" in lines[i]:
var p = lines[i].split(":", true, 1)
var k = p[0].strip_edges()
var v = p[1].strip_edges()
match k:
"name":
out.id = v
"prog", "progress":
out["%"] = float(v.replace("%", ""))
i += 1
# skip comments
elif "<!--" in lines[i]:
pass
# skip code blocks
elif lines[i].begins_with("~~~") or lines[i].begins_with("```"):
var head = lines[i].substr(0, 3)
i += 1
while i < len(lines) and not lines[i].begins_with(head):
i += 1
# heading
elif lines[i].begins_with("#"):
var p = lines[i].split(" ", true, 1)
var id = lines[i].split(" ", true, 1)
var deep = len(id[0])
id = "???" if len(id) == 1 else id[1].strip_edges()
out.chaps += 1
else:
out.words += TE_Util.count_words(lines[i], out.uwords, skip_words)
i += 1
# sort word counts
TE_Util.sort_vals(out.uwords)
var words = PoolStringArray(out.uwords.keys())
var words_top = words
if len(words_top) > 16:
words_top.resize(16)
out.uwords = words_top.join(" ")
var word_lines = [""]
for word in words:
if len(word_lines[-1]) >= 64:
word_lines.append("")
if word_lines[-1]:
word_lines[-1] += " "
word_lines[-1] += word
out.uwords_all = PoolStringArray(word_lines).join("\n")
func _clicked(args):
match args[0]:
"sort_table":
var key = args[1]
if sort_on != key:
sort_on = key
sort_on_index = sort_reverse.keys().find(sort_on)
else:
sort_reverse[key] = not sort_reverse[key]
_sort()
_redraw()
"goto":
var tab = editor.open_file(args[1])
editor.select_file(args[1])
tab.goto_line(args[2])
func _sort():
if sort_reverse[sort_on]:
chapter_info.sort_custom(self, "_sort_chapters_r")
else:
chapter_info.sort_custom(self, "_sort_chapters")
func _sort_chapters(a, b):
return a[sort_on] < b[sort_on]
func _sort_chapters_r(a, b):
return a[sort_on] > b[sort_on]
func _redraw():
clear()
var c1 = Color.white.darkened(.4)
var c2 = Color.white.darkened(.3)
var ch1 = lerp(c1, Color.yellowgreen, .5)
var ch2 = lerp(c2, Color.yellowgreen, .5)
var cols = ["id", "chaps", "words", "uwords", "%", "modified"]
push_align(RichTextLabel.ALIGN_CENTER)
push_table(len(cols))
add_constant_override("table_hseparation", 8)
for id in cols:
push_cell()
push_bold()
push_meta(add_meta(["sort_table", id], "sort on %s" % id))
add_text(id)
if sort_on == id:
push_color(Color.greenyellow.darkened(.25))
add_text("" if sort_reverse[id] else "")
pop()
else:
push_color(Color.white.darkened(.7))
add_text("" if sort_reverse[id] else "")
pop()
pop()
pop()
pop()
for i in len(chapter_info):
var item = chapter_info[i]
var clr = c1 if i%2==0 else c2
var clrh = ch1 if i%2==0 else ch2
# id
push_cell()
push_color(clrh if sort_on_index == 0 else clr)
push_meta(add_meta(["goto", item.path, item.line], item.path + "\n" + item.uwords_all))
add_text(item.id)
pop()
pop()
pop()
# chapters
push_cell()
push_color(clrh if sort_on_index == 1 else clr)
add_text(TE_Util.commas(item.chaps))
pop()
pop()
# word cound
push_cell()
push_color(clrh if sort_on_index == 2 else clr)
add_text(TE_Util.commas(item.words))
pop()
pop()
# unique words
push_cell()
push_color(clrh if sort_on_index == 3 else clr)
add_text(item.uwords)
pop()
pop()
# percent
push_cell()
push_color(clrh if sort_on_index == 4 else clr)
add_text(str(int(item["%"])))
pop()
pop()
# time
push_cell()
push_color(clrh if sort_on_index == 5 else clr)
add_text(item.time_nice)
pop()
pop()
pop()
pop()

View File

@ -1,163 +0,0 @@
tool
extends "res://addons/text_editor/TE_RichTextLabel.gd"
onready var line_edit:LineEdit = get_parent().get_node("c/le")
onready var all_toggle:CheckBox = get_parent().get_node("c/all")
onready var case_toggle:CheckBox = get_parent().get_node("c/case")
var console_urls:Array = []
var last_search:String = ""
func _ready():
var _e
_e = line_edit.connect("text_entered", self, "_text_entered")
# fix fonts
line_edit.add_font_override("font", editor.FONT_R)
all_toggle.add_font_override("font", editor.FONT_R)
case_toggle.add_font_override("font", editor.FONT_R)
func select():
line_edit.grab_focus()
line_edit.grab_click_focus()
line_edit.select_all()
func _clicked(args):
match args[0]:
"goto":
var tab:TextEdit = editor.open_file(args[1])
editor.select_file(args[1])
yield(get_tree(), "idle_frame")
# goto line
var hfrom = int(args[2])
var line = int(args[3])
tab.goto_line(hfrom)
tab.goto_line(line, false)
# select area
var from = int(args[4])
var lenn = int(args[5])
tab.select(line, from, line, from + lenn)
tab.cursor_set_line(line)
tab.cursor_set_column(from)
func _text_entered(search_for:String):
last_search = search_for
clear()
var found:Dictionary = _search(search_for)
var bbcode:PoolStringArray = PoolStringArray()
var fpaths = found.keys()
for k in len(fpaths):
if k != 0:
bbcode.append("")
var file_path:String = fpaths[k]
var l = clr("%s/%s " % [k+1, len(fpaths)], Color.orange) + clr(file_path.get_file(), Color.yellow)
l = meta(l, ["goto", file_path, 0, 0, 0], file_path)
bbcode.append(l)
var all_found = found[file_path]
for j in len(all_found):
var result = found[file_path][j]
var got_lines = result[0]
var highlight_from = result[1]
var line_index = result[2]
var char_index = result[3]
bbcode.append(clr(" %s/%s" % [j+1, len(all_found)], Color.orange))
for i in len(got_lines):
l = ""
var highlight = got_lines[i][0]
var lindex = got_lines[i][1]
var ltext = got_lines[i][2]
if highlight:
# var line:String = ltext
# var head:String = line.substr(0, char_index)
# var midd: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))
# midd = b(clr(midd, Color.white))
# tail = clr(tail, Color.white.darkened(.25))
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:
l = "\t" + clr(str(lindex) + ": ", Color.white.darkened(.65)) + clr(ltext, Color.white.darkened(.5))
if l:
l = meta(l, ["goto", file_path, highlight_from, line_index, char_index, len(search_for)])
bbcode.append(l)
set_bbcode(bbcode.join("\n"))
# get a list of files containging lines
func _search(search_for:String) -> Dictionary:
var out = {}
var search_for_l:String
if case_toggle.pressed:
search_for_l = search_for
else:
search_for_l = search_for.to_lower()
var paths:Array
# search all
if all_toggle.pressed:
paths = editor.file_paths
# only search selected
else:
var sel = editor.get_selected_file()
if not sel:
var err_msg = "no file open to search"
editor.console.err(err_msg)
push_error(err_msg)
return out
else:
paths = [sel]
for path in paths:
var lines = TE_Util.load_text(path).split("\n")
for line_index in len(lines):
var line:String = lines[line_index]
# make lowercase, if case doesn't matter
if not case_toggle.pressed:
line = line.to_lower()
# find index where result is found
var char_index:int = line.find(search_for_l)
if char_index != -1:
if not path in out:
out[path] = []
var preview_lines = [[true, line_index, lines[line_index]]]
var highlight_from:int = line_index
# previous few lines before a blank
for i in range(1, 3):
if line_index-i >= 0:
if not lines[line_index-i].strip_edges():
break
highlight_from = line_index-i
preview_lines.push_front([false, line_index-i, lines[line_index-i]])
# next few lines before a blank
for i in range(1, 3):
if line_index+i < len(lines):
if not lines[line_index+i].strip_edges():
break
preview_lines.push_back([false, line_index+i, lines[line_index+i]])
# lines, index in file, index in line
out[path].append([preview_lines, highlight_from, line_index, char_index])
return out

File diff suppressed because one or more lines are too long

View File

@ -1,26 +1,14 @@
tool tool
extends "res://addons/text_editor/TE_RichTextLabel.gd" extends RichTextLabel
var hscrolls:Dictionary = {} onready var editor:TextEditor = owner
var selected_line:int = 0
var current_file:String = ""
var filter:String = ""
export var p_filter:NodePath
func _ready(): func _ready():
var _e var _e
_e = connect("meta_hover_started", self, "_hovered")
_e = connect("meta_clicked", self, "_clicked")
_e = editor.connect("symbols_updated", self, "_redraw") _e = editor.connect("symbols_updated", self, "_redraw")
_e = editor.connect("tags_updated", self, "_redraw") _e = editor.connect("tags_updated", self, "_redraw")
_e = editor.connect("file_selected", self, "_file_selected")
_e = editor.connect("file_closed", self, "_file_closed")
_e = editor.connect("file_renamed", self, "_file_renamed")
_e = editor.connect("selected_symbol_line", self, "_selected_symbol_line")
_e = get_v_scroll().connect("value_changed", self, "_scrolling")
var le:LineEdit = get_node(p_filter)
_e = le.connect("text_changed", self, "_filter_changed")
le.add_font_override("font", editor.FONT_R)
add_font_override("normal_font", editor.FONT_R) add_font_override("normal_font", editor.FONT_R)
add_font_override("bold_font", editor.FONT_B) add_font_override("bold_font", editor.FONT_B)
@ -29,76 +17,21 @@ func _ready():
call_deferred("_redraw") call_deferred("_redraw")
func _filter_changed(t:String): func _hovered(_id):
filter = t.to_lower() pass
_redraw()
func _selected_symbol_line(line:int): func _clicked(id):
selected_line = clamp(line, 0, get_line_count()) var p = id.split(":", true, 1)
scroll_to_line(clamp(line-1, 0, get_line_count()-1)) var i = int(p[1])
_redraw() match p[0]:
"l":
func _file_selected(file_path:String):
current_file = file_path
yield(get_tree(), "idle_frame")
get_v_scroll().value = hscrolls.get(file_path, 0)
func _file_renamed(old:String, new:String):
current_file = new
yield(get_tree(), "idle_frame")
_redraw()
func _file_closed(file_path:String):
if file_path == current_file:
current_file = ""
_redraw()
func _scrolling(v):
hscrolls[editor.get_selected_file()] = get_v_scroll().value
func _clicked(args:Array):
var te:TextEdit = editor.get_selected_tab() var te:TextEdit = editor.get_selected_tab()
te.cursor_set_line(te.get_line_count()) # force scroll to bottom so selected line will be at top
# select entire symbol block? te.cursor_set_line(i)
if Input.is_key_pressed(KEY_CONTROL):
var tab = editor.get_selected_tab()
var symbols = {} if not tab else tab.symbols
var line_index:int = args[1]
var symbol_index:int = symbols.keys().find(line_index)
var next_line:int
# select sub symbol blocks?
if not Input.is_key_pressed(KEY_SHIFT):
var deep = symbols[line_index].deep
while symbol_index < len(symbols)-1 and symbols.values()[symbol_index+1].deep > deep:
symbol_index += 1
if symbol_index == len(symbols)-1:
next_line = tab.get_line_count()-1
else:
next_line = symbols.keys()[symbol_index+1]-1
tab.select(line_index, 0, next_line, len(tab.get_line(next_line)))
te.goto_line(line_index)
else:
te.goto_line(args[1])
func _redraw(): func _redraw():
var tab = editor.get_selected_tab() var tab = editor.get_selected_tab()
var symbols = {} if not tab else tab.symbols var symbols = {} if not tab else tab.symbols
var spaces = PoolStringArray([
"- ",
" - ",
" - "
])
var colors = PoolColorArray([
Color.white,
Color.white.darkened(.25),
Color.white.darkened(.5)
])
# no symbols # no symbols
if not symbols or len(symbols) == 1: if not symbols or len(symbols) == 1:
@ -106,37 +39,14 @@ func _redraw():
else: else:
var t = PoolStringArray() var t = PoolStringArray()
var i = -1
for line_index in symbols: for line_index in symbols:
i += 1
if line_index == -1: if line_index == -1:
continue # special file chapter continue # special file chapter
var symbol_info = symbols[line_index] var symbol_info = symbols[line_index]
var deep = symbol_info.deep var space = "" if not symbol_info.deep else " ".repeat(symbol_info.deep)
var space = "" if not deep else clr("-".repeat(deep), Color.white.darkened(.75)) var tagged = editor.is_tagged_or_visible(symbol_info.tags)
var cl = Color.white var clr = Color.white.darkened(0.0 if tagged else 0.75).to_html()
t.append(space + "[color=#%s][url=l:%s]%s[/url][/color]" % [clr, line_index, symbol_info.name])
if filter and not filter in symbol_info.name.to_lower():
continue
if symbol_info.name.begins_with("*") and symbol_info.name.ends_with("*"):
cl = editor.get_symbol_color(deep, -.33)
elif symbol_info.name.begins_with('"') and symbol_info.name.ends_with('"'):
cl = editor.get_symbol_color(deep, .33)
else:
cl = editor.get_symbol_color(deep)
if not editor.is_tagged_or_visible(symbol_info.tags):
cl = cl.darkened(.7)
var tags = "" if not symbol_info.tags else PoolStringArray(symbol_info.tags).join(", ")
var text = clr(meta(space + symbol_info.name, [symbol_info, line_index], tags), cl)
if i == selected_line:
text = b(u(text))
t.append(text)
set_bbcode(t.join("\n")) set_bbcode(t.join("\n"))

View File

@ -1,7 +1,7 @@
tool tool
extends TabContainer extends TabContainer
onready var editor:TE_Editor = owner onready var editor:TextEditor = owner
var mouse_over:bool = false var mouse_over:bool = false

View File

@ -1,8 +1,15 @@
tool tool
extends "res://addons/text_editor/TE_RichTextLabel.gd" extends RichTextLabel
onready var editor:TextEditor = owner
var tag_indices:Array = [] # safer to use int in [url=] than str.
func _ready(): func _ready():
var _e var _e
_e = connect("meta_hover_started", self, "_hovered")
_e = connect("meta_hover_ended", self, "_unhover")
_e = connect("meta_clicked", self, "_clicked")
_e = editor.connect("symbols_updated", self, "_redraw") _e = editor.connect("symbols_updated", self, "_redraw")
_e = editor.connect("tags_updated", self, "_redraw") _e = editor.connect("tags_updated", self, "_redraw")
@ -17,36 +24,39 @@ func _ready():
call_deferred("_redraw") call_deferred("_redraw")
func _clicked(args:Array): func _hovered(index):
var tag = args[0] var tag = tag_indices[int(index)]
var was_enabled = editor.is_tag_enabled(tag) var count = editor.tag_counts[tag]
hint_tooltip = "%s x%s" % [tag, count]
if not Input.is_key_pressed(KEY_CONTROL): func _unhover(t):
editor.tags_enabled.clear() hint_tooltip = ""
editor.enable_tag(tag, not was_enabled) func _clicked(id):
var tag = tag_indices[int(id)]
editor.enable_tag(tag, not editor.is_tag_enabled(tag))
#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.tag_counts
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()])
@ -56,23 +66,30 @@ func _redraw():
var count_color1 = Color.tomato.to_html() var count_color1 = Color.tomato.to_html()
var count_color2 = Color.tomato.darkened(.75).to_html() var count_color2 = Color.tomato.darkened(.75).to_html()
for tag in tags: for tag in tags:
var count = editor.tags[tag] var count = editor.tag_counts[tag]
var enabled = editor.is_tag_enabled(tag) var enabled = editor.is_tag_enabled(tag)
var x = tag var x = tag
# if count > 1:
# x = "[color=#%s][i]%s[/i][/color]%s" % [count_color1 if enabled else count_color2, count, tag]
# else:
# x = tag
var color = editor.color_text var color = editor.color_text
var dim = 0.75 var dim = 0.75
if tag in tab_tags: if tag in tab_tags:
color = editor.color_tag color = editor.color_symbol
x = b(x) x = "[b]%s[/b]" % x
dim = 0.6 dim = 0.6
if enabled: if enabled:
x = x x = x
else: else:
x = clr(x, color.darkened(dim)) x = "[color=#%s]%s[/color]" % [color.darkened(dim).to_html(), x]
t.append(meta(x, [tag], "%s x%s" % [tag, count] )) x = "[url=%s]%s[/url]" % [len(tag_indices), x]
t.append(x)
tag_indices.append(tag)
set_bbcode("[center]" + t.join(" ")) set_bbcode("[center]" + t.join(" "))

View File

@ -0,0 +1,734 @@
tool
extends Control
class_name TextEditor
const FONT:DynamicFont = preload("res://addons/text_editor/fonts/font.tres")
const FONT_R:DynamicFont = preload("res://addons/text_editor/fonts/font_r.tres")
const FONT_B:DynamicFont = preload("res://addons/text_editor/fonts/font_b.tres")
const FONT_I:DynamicFont = preload("res://addons/text_editor/fonts/font_i.tres")
const FONT_BI:DynamicFont = preload("res://addons/text_editor/fonts/font_bi.tres")
const PATH_TRASH:String = "res://.trash"
const PATH_TRASH_INFO:String = "res://.trash.json"
const PATH_STATE:String = "res://.text_editor_state.json"
const MAIN_EXTENSIONS:PoolStringArray = PoolStringArray([
"txt", "md", "json", "csv", "cfg", "ini", "yaml"
])
const INTERNAL_EXTENSIONS:PoolStringArray = PoolStringArray([
"gd", "tres", "tscn", "import", "gdignore", "gitignore"
])
const FILE_FILTERS:PoolStringArray = PoolStringArray([
"*.txt ; Text",
"*.md ; Markdown",
"*.json ; JSON",
"*.csv ; Comma Seperated Values",
"*.cfg ; Config",
"*.ini ; Config",
"*.yaml ; YAML",
])
signal updated_file_list()
signal file_opened(file_path)
signal file_closed(file_path)
signal file_selected(file_path)
signal file_saved(file_path)
signal file_renamed(old_path, new_path)
signal symbols_updated()
signal tags_updated()
signal save_files()
signal state_saved()
signal state_loaded()
var plugin = null
var plugin_hint:bool = false
var show:Dictionary = {
dir={
empty=true,
hidden=true,
gdignore=true,
addons=false,
git=false,
import=false,
trash=false
},
file={
hidden=false
}
}
var color_text:Color = Color.white
var color_comment:Color = Color.white.darkened(.6)
var color_symbol:Color = Color.deepskyblue
var color_var:Color = Color.orange
var color_varname:Color = Color.white.darkened(.25)
onready var test_button:Node = $c/c/c/test
onready var tab_parent:TabContainer = $c/div1/div2/c/tab_container
onready var tab_prefab:Node = $file_editor
onready var popup:ConfirmationDialog = $popup
onready var popup_unsaved:ConfirmationDialog = $popup_unsaved
onready var file_dialog:FileDialog = $file_dialog
onready var line_edit:LineEdit = $c/div1/div2/c/line_edit
onready var menu_file:MenuButton = $c/c/c/file_button
onready var menu_view:MenuButton = $c/c/c/view_button
var popup_file:PopupMenu
var popup_view:PopupMenu
var popup_view_dir:PopupMenu = PopupMenu.new()
var popup_view_file:PopupMenu = PopupMenu.new()
var current_directory:String = "res://"
var file_list:Dictionary = {}
var symbols:Dictionary = {}
var tags:Array = []
var tags_enabled:Dictionary = {}
var tag_counts:Dictionary = {}
var exts_enabled:Array = []
var opened:Array = []
var closed:Array = []
func _ready():
if not is_plugin_active():
return
load_state()
# not needed when editor plugin
# get_tree().set_auto_accept_quit(false)
var _e
_e = test_button.connect("pressed", self, "_debug_pressed")
test_button.add_font_override("font", FONT_R)
# popup unsaved
popup_unsaved.get_ok().text = "Ok"
popup_unsaved.get_cancel().text = "Cancel"
var btn = popup_unsaved.add_button("Save and Close", false, "save_and_close")
btn.modulate = Color.yellowgreen
btn.connect("pressed", popup_unsaved, "hide")
TE_Util.dig(popup_unsaved, self, "_apply_fonts")
# menu
menu_file.add_font_override("font", FONT_R)
popup_file = menu_file.get_popup()
popup_file.clear()
popup_file.add_font_override("font", FONT_R)
popup_file.add_item("New File", 100)
popup_file.add_item("New Folder", 200)
popup_file.add_separator()
popup_file.add_item("Open last closed", 300)
_e = popup_file.connect("id_pressed", self, "_menu_file")
# view
menu_view.add_font_override("font", FONT_R)
popup_view = menu_view.get_popup()
popup_view.clear()
popup_view.add_font_override("font", FONT_R)
# view/dir
popup_view_dir.clear()
popup_view_dir.set_name("Directories")
popup_view_dir.add_font_override("font", FONT_R)
popup_view_dir.add_check_item("Hidden", hash("Hidden"))
popup_view_dir.add_check_item("Empty", hash("Empty"))
popup_view_dir.add_check_item(".gdignore", hash(".gdignore"))
popup_view_dir.set_item_checked(0, show.dir.hidden)
popup_view_dir.set_item_checked(1, show.dir.empty)
popup_view_dir.set_item_checked(2, show.dir.gdignore)
popup_view_dir.add_separator()
popup_view_dir.add_check_item("addons/", hash("addons/"))
popup_view_dir.add_check_item(".import/", hash(".import/"))
popup_view_dir.add_check_item(".git/", hash(".git/"))
popup_view_dir.add_check_item(".trash/", hash(".trash/"))
popup_view.add_child(popup_view_dir)
popup_view.add_submenu_item("Directories", "Directories")
_e = popup_view_dir.connect("index_pressed", self, "_menu_view_dir")
# view/file
popup_view_file.clear()
popup_view_file.set_name("Files")
popup_view_file.add_font_override("font", FONT_R)
popup_view_file.add_check_item("Hidden", 0)
popup_view_file.set_item_checked(0, show.file.hidden)
popup_view_file.add_separator()
for i in len(MAIN_EXTENSIONS):
var ext = MAIN_EXTENSIONS[i]
popup_view_file.add_check_item("*." + ext, i+2)
popup_view_file.set_item_checked(i+2, true)
exts_enabled.append(ext)
popup_view_file.add_separator()
for i in len(INTERNAL_EXTENSIONS):
var ext = INTERNAL_EXTENSIONS[i]
var id = i+len(MAIN_EXTENSIONS)+3
popup_view_file.add_check_item("*." + ext, id)
popup_view_file.set_item_checked(id, false)
popup_view.add_child(popup_view_file)
popup_view.add_submenu_item("Files", "Files")
_e = popup_view_file.connect("index_pressed", self, "_menu_view_file")
# file dialog
_e = file_dialog.connect("file_selected", self, "_file_dialog_file")
file_dialog.add_font_override("title_font", FONT_R)
TE_Util.dig(file_dialog, self, "_apply_fonts")
# tab control
_e = tab_parent.connect("tab_changed", self, "_tab_changed")
#
tab_parent.add_font_override("font", FONT_R)
set_directory()
func load_state():
var state:Dictionary = TE_Util.load_json(PATH_STATE)
if not state:
return
var selected
for file_path in state.tabs:
var tab = _open_file(file_path)
tab.set_state(state.tabs[file_path])
if file_path == state.selected:
selected = tab
tab_parent.current_tab = selected.get_index()
current_directory = state.current
for k in state.show.dir:
show.dir[k] = state.show.dir[k]
for k in state.show.file:
show.file[k] = state.show.file[k]
tag_counts = state.tag_counts
tags_enabled = state.tags_enabled
exts_enabled = state.exts_enabled
$c/div1.split_offset = state.div1
$c/div1/div2.split_offset = state.div2
emit_signal("state_loaded")
func save_state():
var state:Dictionary = {
"save_version": "1",
"current": current_directory,
"font_size": FONT.size,
"tabs": {},
"selected": get_selected_file(),
"show": show,
"tags": tags,
"tag_counts": tag_counts,
"tags_enabled": tags_enabled,
"exts_enabled": exts_enabled,
"div1": $c/div1.split_offset,
"div2": $c/div1/div2.split_offset
}
for tab in get_all_tabs():
state.tabs[tab.file_path] = tab.get_state()
TE_Util.save_json(PATH_STATE, state)
emit_signal("state_saved")
func _exit_tree():
save_state()
# not needed when an editor plugin
#func _notification(what):
# match what:
# MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
# for tab in get_all_tabs():
# if tab.modified:
# popup.show()
# return
# get_tree().quit()
func is_plugin_active():
if not Engine.editor_hint:
return true
return plugin_hint and visible
func _input(e):
if not is_plugin_active():
return
if e is InputEventMouseButton and e.control:
if e.button_index == BUTTON_WHEEL_DOWN:
FONT.size = int(max(8, FONT.size - 1))
get_tree().set_input_as_handled()
elif e.button_index == BUTTON_WHEEL_UP:
FONT.size = int(min(64, FONT.size + 1))
get_tree().set_input_as_handled()
func _apply_fonts(n:Node):
if n is Control:
if n.has_font("font"):
n.add_font_override("font", FONT_R)
func _menu_file(id):
match id:
100: popup_create_file() # "New File"
200: popup_create_dir() # "New Folder"
300: open_last_file() # "Open last closed"
func _menu_view_dir(index:int):
var text = popup_view_dir.get_item_text(index)
print(text)
match text:
"Hidden":
show.dir.hidden = not show.dir.hidden
popup_view_dir.set_item_checked(index, show.dir.hidden)
"Empty":
show.dir.empty = not show.dir.empty
popup_view_dir.set_item_checked(index, show.dir.empty)
".gdignore":
show.dir.gdignore = not show.dir.gdignore
popup_view_dir.set_item_checked(index, show.dir.gdignore)
"addons/":
show.dir.addons = not show.dir.addons
popup_view_dir.set_item_checked(index, show.dir.addons)
".import/":
show.dir.import = not show.dir.import
popup_view_dir.set_item_checked(index, show.dir.import)
".git/":
show.dir.git = not show.dir.git
popup_view_dir.set_item_checked(index, show.dir.git)
".trash/":
show.dir.trash = not show.dir.trash
popup_view_dir.set_item_checked(index, show.dir.trash)
refresh_files()
func _menu_view_file(index:int):
# hidden files
if index == 0:
show.file.hidden = not show.file.hidden
popup_view_file.set_item_checked(index, show.file.hidden)
# main extensions
elif index-2 < len(MAIN_EXTENSIONS):
var ext = MAIN_EXTENSIONS[index-2]
var toggled = ext in exts_enabled
if toggled:
exts_enabled.erase(ext)
elif not ext in exts_enabled:
exts_enabled.append(ext)
popup_view_file.set_item_checked(index, not toggled)
refresh_files()
# internal extensions
elif index-3-len(MAIN_EXTENSIONS) < len(INTERNAL_EXTENSIONS):
var ext = INTERNAL_EXTENSIONS[index-3-len(MAIN_EXTENSIONS)]
var toggled = ext in exts_enabled
if toggled:
exts_enabled.erase(ext)
elif not ext in exts_enabled:
exts_enabled.append(ext)
popup_view_file.set_item_checked(index, not toggled)
refresh_files()
func _file_dialog_file(file_path:String):
match file_dialog.get_meta("mode"):
"create_file": create_file(file_path)
"create_dir": create_dir(file_path)
var tab_index:int = -1
func _tab_changed(index:int):
tab_index = index
var node = tab_parent.get_child(index)
if node:
_selected_file_changed(get_selected_file())
else:
_selected_file_changed("")
var last_selected_file:String = ""
func _selected_file_changed(file_path:String):
if file_path != last_selected_file:
last_selected_file = file_path
emit_signal("file_selected", last_selected_file)
func is_tag_enabled(tag:String) -> bool:
return tags_enabled.get(tag, false)
func enable_tag(tag:String, enabled:bool=true):
tags_enabled[tag] = enabled
tags.clear()
for t in tags_enabled:
if tags_enabled[t]:
tags.append(t)
emit_signal("tags_updated")
func is_tagged_or_visible(file_tags:Array) -> bool:
if not len(tags):
return true
for t in tags:
if not t in file_tags:
return false
return true
func is_tagged(file_path:String) -> bool:
var tab = get_tab(file_path)
if tab:
return is_tagged_or_visible(tab.tags.keys())
return false
func is_tagging() -> bool:
return len(tags) > 0
func popup_create_file(dir:String="res://"):
file_dialog.mode = FileDialog.MODE_SAVE_FILE
file_dialog.current_dir = dir
file_dialog.window_title = "Create File"
file_dialog.current_path = "new_file.txt"
file_dialog.filters = FILE_FILTERS
file_dialog.set_meta("mode", "create_file")
file_dialog.show()
func popup_create_dir(dir:String="res://"):
file_dialog.mode = FileDialog.MODE_OPEN_DIR
file_dialog.current_dir = dir
file_dialog.window_title = "Create Folder"
file_dialog.current_path = "New Folder"
file_dialog.set_meta("mode", "create_dir")
file_dialog.show()
func create_file(file_path:String):
var f:File = File.new()
if f.open(file_path, File.WRITE) == OK:
f.store_string("")
f.close()
refresh_files()
open_file(file_path)
select_file(file_path)
else:
push_error("couldnt create %s" % file_path)
func create_dir(file_path:String):
var d:Directory = Directory.new()
if file_path and file_path.begins_with("res://") and not d.file_exists(file_path):
print("creating folder \"%s\"" % file_path)
d.make_dir(file_path)
refresh_files()
func _debug_pressed():
set_directory()
#func _unhandled_key_input(e:InputEventKey):
# if not e.pressed:
# return
#
# if e.control:
# # save
# if e.scancode == KEY_S:
# emit_signal("save_files")
#
# # close/unclose tab
# elif e.scancode == KEY_W:
# if e.shift:
# open_last_file()
# else:
# close_selected()
#
# elif e.scancode == KEY_R:
# sort_files()
#
# else:
# return
#
# get_tree().set_input_as_handled()
func save_files():
emit_signal("save_files")
func get_selected_file() -> String:
var node = get_selected_tab()
return node.file_path if node else ""
func get_tab(file_path:String) -> TextEdit:
for child in tab_parent.get_children():
if child.file_path == file_path:
return child
return null
func get_selected_tab() -> TextEdit:
var i = tab_parent.current_tab
if i >= 0 and i < tab_parent.get_child_count():
return tab_parent.get_child(i) as TextEdit
return null
func get_temporary_tab() -> TextEdit:
for child in tab_parent.get_children():
if child.temporary:
return child
return null
func save_file(file_path:String, text:String):
var f:File = File.new()
var _err = f.open(file_path, File.WRITE)
f.store_string(text)
f.close()
emit_signal("file_saved", file_path)
func open_last_file():
if closed:
var file_path = closed.pop_back()
open_file(file_path)
select_file(file_path)
func close_selected():
var tab = get_selected_tab()
if tab:
tab.close()
else:
print("cant close")
func close_file(file_path:String):
var tab = get_tab(file_path)
if tab:
tab.close()
func _close_file(file_path, remember:bool=true):
if remember:
closed.append(file_path)
var tab = get_tab(file_path)
tab_parent.remove_child(tab)
tab.queue_free()
emit_signal("file_closed", file_path)
func _open_file(file_path:String):
var tab = tab_prefab.duplicate()
tab.visible = true
tab.editor = self
tab_parent.add_child(tab)
tab.set_owner(self)
tab.load_file(file_path)
return tab
func open_file(file_path:String, temporary:bool=false):
var tab = get_tab(file_path)
if tab:
return tab
else:
tab = _open_file(file_path)
if temporary:
tab.temporary = true
else:
opened.append(file_path)
emit_signal("file_opened", file_path)
return tab
func is_opened(file_path:String) -> bool:
return get_tab(file_path) != null
func is_selected(file_path:String) -> bool:
return get_selected_file() == file_path
func recycle_file(file_path:String):
var old_base:String = file_path.substr(len("res://")).get_base_dir()
var p = file_path.get_file().split(".", true, 1)
var old_name:String = p[0]
var old_ext:String = p[1]
var tab = get_tab(file_path)
var new_file = "%s_%s.%s" % [old_name, OS.get_system_time_secs(), old_ext]
var new_path:String = PATH_TRASH.plus_file(old_base).plus_file(new_file)
# create directory
var new_dir = new_path.get_base_dir()
if Directory.new().make_dir_recursive(new_dir) != OK:
print("couldn't remove %s" % file_path)
return
# save recovery information
var trash_info = TE_Util.load_json(PATH_TRASH_INFO)
trash_info[new_path] = file_path
TE_Util.save_json(PATH_TRASH_INFO, trash_info)
# remove by renaming
rename_file(file_path, new_path)
if tab:
tab_parent.remove_child(tab)
tab.queue_free()
if opened:
select_file(opened[-1])
func rename_file(old_path:String, new_path:String):
if old_path == new_path or not old_path or not new_path:
return
if File.new().file_exists(new_path):
push_error("can't rename %s to %s. file already exists." % [old_path, new_path])
return
var selected = get_selected_file()
if Directory.new().rename(old_path, new_path) == OK:
refresh_files()
if selected == old_path:
_selected_file_changed(new_path)
emit_signal("file_renamed", old_path, new_path)
else:
push_error("couldn't rename %s to %s." % [old_path, new_path])
func select_file(file_path:String):
var temp = get_temporary_tab()
if temp:
if temp.file_path == file_path:
temp.temporary = false
else:
temp.close()
if not is_opened(file_path):
open_file(file_path, true)
# select current tab
tab_parent.current_tab = get_tab(file_path).get_index()
_selected_file_changed(file_path)
func set_directory(path:String=current_directory):
var gpath = ProjectSettings.globalize_path(path)
var dname = gpath.get_file()
current_directory = path
file_dialog.current_dir = path
refresh_files()
func _file_symbols_updated(file_path:String):
var tg = get_tab(file_path).tags
tags_enabled.clear()
for tag in tg:
if not tag in tags_enabled:
tags_enabled[tag] = false
tag_counts.clear()
for child in get_all_tabs():
for t in child.tags:
if not t in tag_counts:
tag_counts[t] = child.tags[t]
else:
tag_counts[t] += child.tags[t]
emit_signal("symbols_updated")
func get_all_tabs() -> Array:
return tab_parent.get_children()
func refresh_files():
# ext_counts.clear()
# dirs.clear()
file_list.clear()
var dir = Directory.new()
if dir.open(current_directory) == OK:
_scan_dir("", current_directory, dir, file_list)
emit_signal("updated_file_list")
else:
push_error("error trying to load %s." % current_directory)
func show_dir(fname:String, base_dir:String) -> bool:
if not show.dir.gdignore and File.new().file_exists(base_dir.plus_file(".gdignore")):
return false
if fname.begins_with("."):
if not show.dir.hidden: return false
if not show.dir.import and fname == ".import": return false
if not show.dir.git and fname == ".git": return false
if not show.dir.trash and fname == ".trash": return false
else:
if not show.dir.addons and fname == "addons": return false
return true
func show_file(fname:String) -> bool:
if fname.begins_with("."):
if not show.file.hidden: return false
var ext = get_extension(fname)
return ext in exts_enabled
func _scan_dir(id:String, path:String, dir:Directory, last_dir:Dictionary):
var _e = dir.list_dir_begin(true, false)
var a_dirs_and_files = {}
var a_files = []
var a_dirs = []
var info = { file_path=path, all=a_dirs_and_files, files=a_files, dirs=a_dirs, open=true }
var fname = dir.get_next()
while fname:
var file_path = dir.get_current_dir().plus_file(fname)
if dir.current_is_dir():
if show_dir(fname, file_path.get_base_dir()):
var sub_dir = Directory.new()
sub_dir.open(file_path)
_scan_dir(fname, file_path, sub_dir, a_dirs_and_files)
else:
if show_file(fname):
a_dirs_and_files[fname] = file_path
fname = dir.get_next()
dir.list_dir_end()
# is empty? ignore
if id and not (show.dir.empty or a_dirs_and_files):
return
# add to last
last_dir[id] = info
for p in a_dirs_and_files:
if a_dirs_and_files[p] is Dictionary:
a_dirs.append(p)
else:
a_files.append(a_dirs_and_files[p])
sort_on_ext(a_dirs)
sort_on_ext(a_files)
func sort_on_ext(items:Array):
var sorted = []
for a in items:
var k = a.get_file()
if "." in k:
k = k.split(".", true, 1)
k = k[1] + k[0]
sorted.append([k, a])
sorted.sort_custom(self, "_sort_on_ext")
for i in len(items):
items[i] = sorted[i][1]
return items
func _sort_on_ext(a, b):
return a[0] < b[0]
static func get_extension(file_path:String) -> String:
var file = file_path.get_file()
if "." in file:
return file.split(".", true, 1)[1]
return ""
static func get_extension_helper(file_path:String) -> TE_ExtensionHelper:
var ext:String = get_extension(file_path).replace(".", "_")
var ext_path:String = "res://addons/text_editor/ext/ext_%s.gd" % ext
if File.new().file_exists(ext_path):
return load(ext_path).new()
return load("res://addons/text_editor/ext/TE_ExtensionHelper.gd").new()

View File

@ -1,77 +1,5 @@
class_name TE_Util class_name TE_Util
class Sorter:
var d:Dictionary
var a:Array = []
func _init(dict:Dictionary):
d = dict
for k in d:
a.append([k, d[k]])
func on_keys(reverse:bool=false):
a.sort_custom(self, "_sort_keys_rev" if reverse else "_sort_keys")
return _out()
func on_vals(reverse:bool=false):
a.sort_custom(self, "_sort_vals_rev" if reverse else "_sort_vals")
return _out()
func _sort_keys(a, b): return a[0] > b[0]
func _sort_keys_rev(a, b): return a[0] < b[0]
func _sort_vals(a, b): return a[1] > b[1]
func _sort_vals_rev(a, b): return a[1] < b[1]
func _out() -> Dictionary:
d.clear()
for item in a:
d[item[0]] = item[1]
return d
static func sort_keys(d:Dictionary, reverse:bool=false): return Sorter.new(d).on_keys(reverse)
static func sort_vals(d:Dictionary, reverse:bool=false): return Sorter.new(d).on_vals(reverse)
static func count_words(text:String, counter:Dictionary, skip_words=null, stop_words:bool=true):
var word_count:int = 0
for sentence in text.split("."):
for word in sentence.split(" "):
word = _sanitize_word(word)
if not word: continue
if stop_words and word in TE_StopWords.STOP_WORDS: continue
if skip_words and word in skip_words: continue
word_count += 1
if not word in counter:
counter[word] = 1
else:
counter[word] += 1
return word_count
static func _sanitize_word(word:String):
var out = ""
var has_letter = false
for c in word.to_lower():
if c in "abcdefghijklmnopqrstuvwxyz":
out += c
has_letter = true
elif c in "-'0123456789":
out += c
if not has_letter:
return ""
if out.ends_with("'s"):
return out.substr(0, len(out)-2)
return out
static func to_var(s:String) -> String:
return s.to_lower().replace(" ", "_")
static func load_text(path:String) -> String: static func load_text(path:String) -> String:
var f:File = File.new() var f:File = File.new()
if f.file_exists(path): if f.file_exists(path):
@ -93,16 +21,6 @@ static func load_json(path:String, loud:bool=false) -> Dictionary:
push_error("no json at \"%s\"" % path) push_error("no json at \"%s\"" % path)
return {} return {}
static func load_image(path:String) -> ImageTexture:
var f:File = File.new()
if f.file_exists(path):
var image:Image = Image.new()
image.load(path)
var texture:ImageTexture = ImageTexture.new()
texture.create_from_image(image)
return texture
return null
static func save_json(path:String, data:Dictionary): static func save_json(path:String, data:Dictionary):
var f:File = File.new() var f:File = File.new()
f.open(path, File.WRITE) f.open(path, File.WRITE)
@ -139,55 +57,23 @@ static func get_whitespace_tail(t:String):
var length = len(t) - len(t.strip_edges(false, true)) var length = len(t) - len(t.strip_edges(false, true))
return t.substr(len(t)-length) return t.substr(len(t)-length)
const _dig = {depth=0}
static func get_dig_depth() -> int:
return _dig.depth
static func dig_for(d, property:String, value):
var depth:int = 0
if d is Dictionary:
return _dig_for_dict(d, property, value, depth)
# elif d is Node:
# return _dig_for_node(d, propert, value, depth)
return null
static func _dig_for_dict(d:Dictionary, property:String, value, depth:int):
_dig.depth = depth
if property in d and d[property] == value:
return d
for k in d:
if d[k] is Dictionary:
var got = _dig_for_dict(d[k], property, value, depth+1)
if got != null:
return got
return null
#static func _dig_for_node(d:Node, f:FuncRef, depth:int):
# _dig.depth = depth
# f.call_func(d)
# for i in d.get_child_count():
# _dig_node(d.get_child(i), f, depth+1)
static func dig(d, obj:Object, fname:String): static func dig(d, obj:Object, fname:String):
var f:FuncRef = funcref(obj, fname) var f = funcref(obj, fname)
var depth:int = 0
if d is Dictionary: if d is Dictionary:
_dig_dict(d, f, depth) _dig_dict(d, f)
elif d is Node: elif d is Node:
_dig_node(d, f, depth) _dig_node(d, f)
static func _dig_dict(d:Dictionary, f:FuncRef, depth:int): static func _dig_dict(d:Dictionary, f:FuncRef):
_dig.depth = depth
f.call_func(d) f.call_func(d)
for k in d: for k in d:
if d[k] is Dictionary: if d[k] is Dictionary:
_dig_dict(d[k], f, depth+1) _dig_dict(d[k], f)
static func _dig_node(d:Node, f:FuncRef, depth:int): static func _dig_node(d:Node, f:FuncRef):
_dig.depth = depth
f.call_func(d) f.call_func(d)
for i in d.get_child_count(): for i in d.get_child_count():
_dig_node(d.get_child(i), f, depth+1) _dig_node(d.get_child(i), f)
static func file_size(path:String) -> String: static func file_size(path:String) -> String:
var f:File = File.new() var f:File = File.new()
@ -197,24 +83,6 @@ static func file_size(path:String) -> String:
return String.humanize_size(bytes) return String.humanize_size(bytes)
return "-1" return "-1"
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)
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:
# return c.from_hsv(c.h, c.s * s, c.v * v, c.a)
#static func sort(d, reverse:bool=false): #static func sort(d, reverse:bool=false):
# return Dict.new(d).sort(reverse) # return Dict.new(d).sort(reverse)
# #

View File

@ -1,7 +1,6 @@
[gd_scene load_steps=29 format=2] [gd_scene load_steps=16 format=2]
[ext_resource path="res://addons/text_editor/TE_Console.gd" type="Script" id=1] [ext_resource path="res://addons/text_editor/TE_TextEditor.gd" type="Script" id=2]
[ext_resource path="res://addons/text_editor/TE_Editor.gd" type="Script" id=2]
[ext_resource path="res://addons/text_editor/TE_FilesList.gd" type="Script" id=3] [ext_resource path="res://addons/text_editor/TE_FilesList.gd" type="Script" id=3]
[ext_resource path="res://addons/text_editor/TE_FileEditor.gd" type="Script" id=4] [ext_resource path="res://addons/text_editor/TE_FileEditor.gd" type="Script" id=4]
[ext_resource path="res://addons/text_editor/TE_SymbolsList.gd" type="Script" id=5] [ext_resource path="res://addons/text_editor/TE_SymbolsList.gd" type="Script" id=5]
@ -14,37 +13,14 @@
[ext_resource path="res://addons/text_editor/fonts/font_r.tres" type="DynamicFont" id=12] [ext_resource path="res://addons/text_editor/fonts/font_r.tres" type="DynamicFont" id=12]
[ext_resource path="res://addons/text_editor/fonts/font_bi.tres" type="DynamicFont" id=13] [ext_resource path="res://addons/text_editor/fonts/font_bi.tres" type="DynamicFont" id=13]
[ext_resource path="res://addons/text_editor/fonts/font.tres" type="DynamicFont" id=14] [ext_resource path="res://addons/text_editor/fonts/font.tres" type="DynamicFont" id=14]
[ext_resource path="res://addons/text_editor/TE_Search.gd" type="Script" id=15]
[ext_resource path="res://addons/text_editor/TE_MetaTabs.gd" type="Script" id=16]
[ext_resource path="res://addons/text_editor/TE_ScriptInfo.gd" type="Script" id=17]
[ext_resource path="res://addons/text_editor/TE_FileInfoLabel.gd" type="Script" id=18]
[ext_resource path="res://addons/text_editor/TE_RichTextLabel.gd" type="Script" id=19]
[ext_resource path="res://addons/text_editor/te_empty_style.tres" type="StyleBox" id=20]
[sub_resource type="Theme" id=8] [sub_resource type="Theme" id=1]
[sub_resource type="Theme" id=9]
TooltipLabel/fonts/font = ExtResource( 12 ) TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=10] [sub_resource type="Theme" id=2]
TooltipLabel/fonts/font = ExtResource( 12 ) TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=11] [node name="text_editor" type="Control"]
TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=12]
TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=13]
TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=14]
TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=15]
TooltipLabel/fonts/font = ExtResource( 12 )
[node name="editor" type="Control"]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
size_flags_horizontal = 3 size_flags_horizontal = 3
@ -53,13 +29,6 @@ script = ExtResource( 2 )
__meta__ = { __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
p_tab_parent = NodePath("c/div1/div2/c/c/c2/tab_container")
p_tab_prefab = NodePath("file_editor")
p_console = NodePath("c/div1/div2/c/c/c/meta_tabs/console")
p_progress_bar = NodePath("c/c/c/progress")
p_menu_file = NodePath("c/c/c/file")
p_menu_view = NodePath("c/c/c/view")
p_menu_insert = NodePath("c/c/c/insert")
[node name="file_editor" type="TextEdit" parent="."] [node name="file_editor" type="TextEdit" parent="."]
visible = false visible = false
@ -71,7 +40,6 @@ margin_right = 214.0
margin_bottom = 30.0 margin_bottom = 30.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
theme = SubResource( 8 )
custom_fonts/font = ExtResource( 14 ) custom_fonts/font = ExtResource( 14 )
highlight_current_line = true highlight_current_line = true
syntax_highlighting = true syntax_highlighting = true
@ -79,7 +47,6 @@ 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 )
@ -93,33 +60,33 @@ __meta__ = {
[node name="c" type="PanelContainer" parent="c"] [node name="c" type="PanelContainer" parent="c"]
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 38.0 margin_bottom = 34.0
[node name="c" type="HBoxContainer" parent="c/c"] [node name="c" type="HBoxContainer" parent="c/c"]
margin_left = 7.0 margin_left = 7.0
margin_top = 7.0 margin_top = 7.0
margin_right = 1017.0 margin_right = 1017.0
margin_bottom = 31.0 margin_bottom = 27.0
[node name="test" type="Button" parent="c/c/c"] [node name="test" type="Button" parent="c/c/c"]
margin_right = 12.0 margin_right = 12.0
margin_bottom = 24.0 margin_bottom = 20.0
text = "⟳" text = "⟳"
[node name="file" type="MenuButton" parent="c/c/c"] [node name="file_button" type="MenuButton" parent="c/c/c"]
margin_left = 16.0 margin_left = 16.0
margin_right = 48.0 margin_right = 48.0
margin_bottom = 24.0 margin_bottom = 20.0
text = "file" text = "file"
items = [ "New File", null, 0, false, false, 0, 0, null, "", false, "Extensions", null, 0, false, false, 1, 0, null, "Extensions", false, "New File", null, 0, false, false, 2, 0, null, "", false, "Extensions", null, 0, false, false, 3, 0, null, "Extensions", false ] items = [ "New File", null, 0, false, false, 0, 0, null, "", false, "Extensions", null, 0, false, false, 1, 0, null, "Extensions", false, "New File", null, 0, false, false, 2, 0, null, "", false, "Extensions", null, 0, false, false, 3, 0, null, "Extensions", false ]
__meta__ = { __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="view" type="MenuButton" parent="c/c/c"] [node name="view_button" type="MenuButton" parent="c/c/c"]
margin_left = 52.0 margin_left = 52.0
margin_right = 93.0 margin_right = 93.0
margin_bottom = 24.0 margin_bottom = 20.0
focus_mode = 2 focus_mode = 2
text = "view" text = "view"
items = [ "New File", null, 0, false, false, 0, 0, null, "", false, "Extensions", null, 0, false, false, 1, 0, null, "Extensions", false, "New File", null, 0, false, false, 2, 0, null, "", false, "Extensions", null, 0, false, false, 3, 0, null, "Extensions", false ] items = [ "New File", null, 0, false, false, 0, 0, null, "", false, "Extensions", null, 0, false, false, 1, 0, null, "Extensions", false, "New File", null, 0, false, false, 2, 0, null, "", false, "Extensions", null, 0, false, false, 3, 0, null, "Extensions", false ]
@ -127,56 +94,8 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="insert" type="MenuButton" parent="c/c/c"]
margin_left = 97.0
margin_right = 146.0
margin_bottom = 24.0
focus_mode = 2
text = "insert"
items = [ "New File", null, 0, false, false, 0, 0, null, "", false, "Extensions", null, 0, false, false, 1, 0, null, "Extensions", false, "New File", null, 0, false, false, 2, 0, null, "", false, "Extensions", null, 0, false, false, 3, 0, null, "Extensions", false ]
__meta__ = {
"_edit_use_anchors_": false
}
[node name="word_wrap" type="CheckBox" parent="c/c/c"]
margin_left = 150.0
margin_right = 208.0
margin_bottom = 24.0
text = "wrap"
[node name="tab_colors" type="CheckBox" parent="c/c/c"]
margin_left = 212.0
margin_right = 303.0
margin_bottom = 24.0
text = "tab colors"
[node name="space" type="Control" parent="c/c/c"]
margin_left = 307.0
margin_right = 971.0
margin_bottom = 24.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="progress" type="ProgressBar" parent="c/c/c"]
visible = false
margin_left = 878.0
margin_right = 978.0
margin_bottom = 24.0
rect_min_size = Vector2( 100, 0 )
size_flags_vertical = 3
[node name="version" type="Label" parent="c/c/c"]
modulate = Color( 1, 1, 1, 0.521569 )
margin_left = 975.0
margin_top = 3.0
margin_right = 1010.0
margin_bottom = 20.0
custom_fonts/font = ExtResource( 12 )
text = "v1.12"
align = 2
[node name="div1" type="HSplitContainer" parent="c"] [node name="div1" type="HSplitContainer" parent="c"]
margin_top = 38.0 margin_top = 34.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 600.0 margin_bottom = 600.0
size_flags_vertical = 3 size_flags_vertical = 3
@ -187,7 +106,7 @@ __meta__ = {
[node name="c2" type="PanelContainer" parent="c/div1"] [node name="c2" type="PanelContainer" parent="c/div1"]
margin_right = 206.0 margin_right = 206.0
margin_bottom = 562.0 margin_bottom = 566.0
rect_min_size = Vector2( 200, 0 ) rect_min_size = Vector2( 200, 0 )
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
@ -196,31 +115,16 @@ size_flags_vertical = 3
margin_left = 7.0 margin_left = 7.0
margin_top = 7.0 margin_top = 7.0
margin_right = 199.0 margin_right = 199.0
margin_bottom = 555.0 margin_bottom = 559.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
[node name="c" type="VBoxContainer" parent="c/div1/c2/c"] [node name="list_files" type="RichTextLabel" parent="c/div1/c2/c"]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="filter" type="LineEdit" parent="c/div1/c2/c/c"]
margin_right = 192.0
margin_bottom = 27.0
custom_fonts/font = ExtResource( 12 )
clear_button_enabled = true
placeholder_text = "Filter"
[node name="list_files" type="RichTextLabel" parent="c/div1/c2/c/c"]
margin_top = 31.0
margin_right = 192.0
margin_bottom = 548.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
theme = SubResource( 9 ) theme = SubResource( 1 )
custom_fonts/bold_italics_font = ExtResource( 13 ) custom_fonts/bold_italics_font = ExtResource( 13 )
custom_fonts/italics_font = ExtResource( 10 ) custom_fonts/italics_font = ExtResource( 10 )
custom_fonts/bold_font = ExtResource( 11 ) custom_fonts/bold_font = ExtResource( 11 )
@ -231,24 +135,23 @@ script = ExtResource( 3 )
__meta__ = { __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
p_filter = NodePath("../filter")
[node name="file_popup" type="PopupMenu" parent="c/div1/c2/c/c/list_files"] [node name="file_popup" type="PopupMenu" parent="c/div1/c2/c/list_files"]
margin_right = 20.0 margin_right = 20.0
margin_bottom = 20.0 margin_bottom = 20.0
custom_fonts/font = ExtResource( 14 ) custom_fonts/font = ExtResource( 14 )
items = [ "Rename", null, 0, false, false, 0, 0, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Remove", null, 0, false, false, 2, 0, null, "", false ] items = [ "Rename", null, 0, false, false, 0, 0, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Remove", null, 0, false, false, 2, 0, null, "", false ]
[node name="dir_popup" type="PopupMenu" parent="c/div1/c2/c/c/list_files"] [node name="dir_popup" type="PopupMenu" parent="c/div1/c2/c/list_files"]
margin_right = 20.0 margin_right = 20.0
margin_bottom = 20.0 margin_bottom = 20.0
custom_fonts/font = ExtResource( 14 ) custom_fonts/font = ExtResource( 14 )
items = [ "New File", null, 0, false, false, 0, 0, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Remove", null, 0, false, false, 2, 0, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Tint Yellow", null, 0, false, false, 4, 0, null, "", false, "Tint Red", null, 0, false, false, 5, 0, null, "", false, "Tint Blue", null, 0, false, false, 6, 0, null, "", false, "Tint Green", null, 0, false, false, 7, 0, null, "", false, "Reset Tint", null, 0, false, false, 8, 0, null, "", false ] items = [ "New File", null, 0, false, false, 0, 0, null, "", false, "New Folder", null, 0, false, false, 1, 0, null, "", false ]
[node name="div2" type="HSplitContainer" parent="c/div1"] [node name="div2" type="HSplitContainer" parent="c/div1"]
margin_left = 218.0 margin_left = 218.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 562.0 margin_bottom = 566.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
split_offset = -80 split_offset = -80
@ -258,37 +161,22 @@ __meta__ = {
[node name="c" type="VBoxContainer" parent="c/div1/div2"] [node name="c" type="VBoxContainer" parent="c/div1/div2"]
margin_right = 614.0 margin_right = 614.0
margin_bottom = 562.0 margin_bottom = 566.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
[node name="line_edit" type="LineEdit" parent="c/div1/div2/c"] [node name="line_edit" type="LineEdit" parent="c/div1/div2/c"]
visible = false visible = false
margin_right = 614.0 margin_right = 614.0
margin_bottom = 32.0 margin_bottom = 24.0
custom_fonts/font = ExtResource( 12 ) custom_fonts/font = ExtResource( 12 )
script = ExtResource( 8 ) script = ExtResource( 8 )
[node name="c" type="VSplitContainer" parent="c/div1/div2/c"] [node name="tab_container" type="TabContainer" parent="c/div1/div2/c"]
margin_right = 614.0 margin_right = 614.0
margin_bottom = 562.0 margin_bottom = 539.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
split_offset = 100
[node name="c2" type="VBoxContainer" parent="c/div1/div2/c/c"]
margin_right = 614.0
margin_bottom = 375.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="tab_container" type="TabContainer" parent="c/div1/div2/c/c/c2"]
margin_right = 614.0
margin_bottom = 353.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_constants/top_margin = 0
custom_constants/side_margin = 0
custom_fonts/font = ExtResource( 12 ) custom_fonts/font = ExtResource( 12 )
tab_align = 0 tab_align = 0
drag_to_rearrange_enabled = true drag_to_rearrange_enabled = true
@ -297,220 +185,22 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="c" type="HBoxContainer" parent="c/div1/div2/c/c/c2"] [node name="meta" type="RichTextLabel" parent="c/div1/div2/c"]
margin_top = 357.0 margin_top = 543.0
margin_right = 614.0 margin_right = 614.0
margin_bottom = 375.0 margin_bottom = 566.0
size_flags_horizontal = 3
script = ExtResource( 18 )
[node name="l" type="RichTextLabel" parent="c/div1/div2/c/c/c2/c"]
margin_right = 202.0
margin_bottom = 18.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_fonts/bold_italics_font = ExtResource( 13 ) custom_fonts/bold_italics_font = ExtResource( 13 )
custom_fonts/italics_font = ExtResource( 10 ) custom_fonts/italics_font = ExtResource( 10 )
custom_fonts/bold_font = ExtResource( 11 ) custom_fonts/bold_font = ExtResource( 11 )
custom_fonts/normal_font = ExtResource( 12 ) custom_fonts/normal_font = ExtResource( 12 )
custom_styles/focus = ExtResource( 20 )
custom_styles/normal = ExtResource( 20 )
bbcode_enabled = true bbcode_enabled = true
fit_content_height = true fit_content_height = true
script = ExtResource( 19 )
[node name="m" type="RichTextLabel" parent="c/div1/div2/c/c/c2/c"]
margin_left = 206.0
margin_right = 408.0
margin_bottom = 18.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_fonts/bold_italics_font = ExtResource( 13 )
custom_fonts/italics_font = ExtResource( 10 )
custom_fonts/bold_font = ExtResource( 11 )
custom_fonts/normal_font = ExtResource( 12 )
custom_styles/focus = ExtResource( 20 )
custom_styles/normal = ExtResource( 20 )
bbcode_enabled = true
fit_content_height = true
script = ExtResource( 19 )
[node name="r" type="RichTextLabel" parent="c/div1/div2/c/c/c2/c"]
margin_left = 412.0
margin_right = 614.0
margin_bottom = 18.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_fonts/bold_italics_font = ExtResource( 13 )
custom_fonts/italics_font = ExtResource( 10 )
custom_fonts/bold_font = ExtResource( 11 )
custom_fonts/normal_font = ExtResource( 12 )
custom_styles/focus = ExtResource( 20 )
custom_styles/normal = ExtResource( 20 )
bbcode_enabled = true
fit_content_height = true
script = ExtResource( 19 )
[node name="c" type="Control" parent="c/div1/div2/c/c"]
margin_top = 387.0
margin_right = 614.0
margin_bottom = 562.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="meta_tabs" type="TabContainer" parent="c/div1/div2/c/c/c"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource( 16 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="console" type="RichTextLabel" parent="c/div1/div2/c/c/c/meta_tabs"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 4.0
margin_top = 32.0
margin_right = -4.0
margin_bottom = -4.0
size_flags_horizontal = 3
size_flags_vertical = 3
theme = SubResource( 10 )
custom_fonts/bold_italics_font = ExtResource( 13 )
custom_fonts/italics_font = ExtResource( 10 )
custom_fonts/bold_font = ExtResource( 11 )
custom_fonts/normal_font = ExtResource( 12 )
bbcode_enabled = true
meta_underlined = false
text = "active: False
"
script = ExtResource( 1 )
[node name="meta" type="RichTextLabel" parent="c/div1/div2/c/c/c/meta_tabs"]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 4.0
margin_top = 32.0
margin_right = -4.0
margin_bottom = -4.0
size_flags_horizontal = 3
size_flags_vertical = 3
theme = SubResource( 11 )
custom_constants/table_hseparation = 16
custom_fonts/bold_italics_font = ExtResource( 13 )
custom_fonts/italics_font = ExtResource( 10 )
custom_fonts/bold_font = ExtResource( 11 )
custom_fonts/normal_font = ExtResource( 12 )
bbcode_enabled = true
script = ExtResource( 9 ) script = ExtResource( 9 )
[node name="search" type="VBoxContainer" parent="c/div1/div2/c/c/c/meta_tabs"]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 4.0
margin_top = 32.0
margin_right = -4.0
margin_bottom = -4.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="c" type="HBoxContainer" parent="c/div1/div2/c/c/c/meta_tabs/search"]
margin_right = 606.0
margin_bottom = 27.0
[node name="le" type="LineEdit" parent="c/div1/div2/c/c/c/meta_tabs/search/c"]
margin_right = 409.0
margin_bottom = 27.0
size_flags_horizontal = 3
custom_fonts/font = ExtResource( 12 )
[node name="all" type="CheckBox" parent="c/div1/div2/c/c/c/meta_tabs/search/c"]
margin_left = 413.0
margin_right = 504.0
margin_bottom = 27.0
custom_fonts/font = ExtResource( 12 )
text = "all files"
[node name="case" type="CheckBox" parent="c/div1/div2/c/c/c/meta_tabs/search/c"]
margin_left = 508.0
margin_right = 606.0
margin_bottom = 27.0
custom_fonts/font = ExtResource( 12 )
text = "match case"
[node name="rte" type="RichTextLabel" parent="c/div1/div2/c/c/c/meta_tabs/search"]
margin_top = 31.0
margin_right = 606.0
margin_bottom = 139.0
size_flags_horizontal = 3
size_flags_vertical = 3
theme = SubResource( 12 )
custom_fonts/bold_italics_font = ExtResource( 13 )
custom_fonts/italics_font = ExtResource( 10 )
custom_fonts/bold_font = ExtResource( 11 )
custom_fonts/normal_font = ExtResource( 12 )
bbcode_enabled = true
meta_underlined = false
script = ExtResource( 15 )
[node name="sys" type="VBoxContainer" parent="c/div1/div2/c/c/c/meta_tabs"]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 4.0
margin_top = 32.0
margin_right = -4.0
margin_bottom = -4.0
[node name="update" type="Button" parent="c/div1/div2/c/c/c/meta_tabs/sys"]
margin_right = 606.0
margin_bottom = 23.0
size_flags_horizontal = 3
custom_fonts/font = ExtResource( 12 )
text = "⟳"
[node name="sys" type="RichTextLabel" parent="c/div1/div2/c/c/c/meta_tabs/sys"]
margin_top = 27.0
margin_right = 606.0
margin_bottom = 239.0
size_flags_horizontal = 3
size_flags_vertical = 3
theme = SubResource( 13 )
custom_constants/table_hseparation = 101
custom_fonts/bold_italics_font = ExtResource( 13 )
custom_fonts/italics_font = ExtResource( 10 )
custom_fonts/bold_font = ExtResource( 11 )
custom_fonts/normal_font = ExtResource( 12 )
bbcode_enabled = true
meta_underlined = false
text = "idwords ⯆unique"
script = ExtResource( 17 )
[node name="image" type="VBoxContainer" parent="c/div1/div2/c/c/c/meta_tabs"]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 4.0
margin_top = 32.0
margin_right = -4.0
margin_bottom = -4.0
[node name="image" type="TextureRect" parent="c/div1/div2/c/c/c/meta_tabs/image"]
margin_right = 606.0
margin_bottom = 239.0
size_flags_horizontal = 3
size_flags_vertical = 3
expand = true
stretch_mode = 6
[node name="c2" type="PanelContainer" parent="c/div1/div2"] [node name="c2" type="PanelContainer" parent="c/div1/div2"]
margin_left = 626.0 margin_left = 626.0
margin_right = 806.0 margin_right = 806.0
margin_bottom = 562.0 margin_bottom = 566.0
rect_min_size = Vector2( 100, 0 ) rect_min_size = Vector2( 100, 0 )
size_flags_vertical = 3 size_flags_vertical = 3
@ -518,38 +208,19 @@ size_flags_vertical = 3
margin_left = 7.0 margin_left = 7.0
margin_top = 7.0 margin_top = 7.0
margin_right = 173.0 margin_right = 173.0
margin_bottom = 555.0 margin_bottom = 559.0
custom_constants/autohide = 0 custom_constants/autohide = 0
split_offset = 180
[node name="c" type="Panel" parent="c/div1/div2/c2/c"] [node name="c" type="Panel" parent="c/div1/div2/c2/c"]
margin_right = 166.0 margin_right = 166.0
margin_bottom = 448.0 margin_bottom = 270.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
[node name="c" type="VBoxContainer" parent="c/div1/div2/c2/c/c"] [node name="list_symbols" type="RichTextLabel" parent="c/div1/div2/c2/c/c"]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
__meta__ = {
"_edit_use_anchors_": false
}
[node name="filter" type="LineEdit" parent="c/div1/div2/c2/c/c/c"]
margin_right = 166.0
margin_bottom = 27.0
custom_fonts/font = ExtResource( 12 )
clear_button_enabled = true
placeholder_text = "Symbol Filter"
[node name="list_symbols" type="RichTextLabel" parent="c/div1/div2/c2/c/c/c"]
margin_top = 31.0
margin_right = 166.0
margin_bottom = 448.0
size_flags_vertical = 3
theme = SubResource( 14 )
custom_fonts/bold_italics_font = ExtResource( 13 ) custom_fonts/bold_italics_font = ExtResource( 13 )
custom_fonts/italics_font = ExtResource( 10 ) custom_fonts/italics_font = ExtResource( 10 )
custom_fonts/bold_font = ExtResource( 11 ) custom_fonts/bold_font = ExtResource( 11 )
@ -562,12 +233,11 @@ script = ExtResource( 5 )
__meta__ = { __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
p_filter = NodePath("../filter")
[node name="c2" type="Panel" parent="c/div1/div2/c2/c"] [node name="c2" type="Panel" parent="c/div1/div2/c2/c"]
margin_top = 460.0 margin_top = 282.0
margin_right = 166.0 margin_right = 166.0
margin_bottom = 548.0 margin_bottom = 552.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
@ -576,7 +246,7 @@ anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
theme = SubResource( 15 ) theme = SubResource( 2 )
custom_fonts/bold_italics_font = ExtResource( 13 ) custom_fonts/bold_italics_font = ExtResource( 13 )
custom_fonts/italics_font = ExtResource( 10 ) custom_fonts/italics_font = ExtResource( 10 )
custom_fonts/bold_font = ExtResource( 11 ) custom_fonts/bold_font = ExtResource( 11 )
@ -626,7 +296,3 @@ current_path = "res://test_files/"
__meta__ = { __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="popup_tab_menu" type="PopupMenu" parent="."]
margin_right = 124.0
margin_bottom = 112.0

View File

@ -4,15 +4,12 @@ class_name TE_ExtensionHelper
var symbols:Dictionary = {} var symbols:Dictionary = {}
func get_tab() -> String: func generate_meta(t:TextEdit, r:TE_RichTextLabel):
return " "
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)))
var lines = TE_Util.commas(len(TE_Util.split_many(t.text, ".?!\n", false))) var lines = TE_Util.commas(len(TE_Util.split_many(t.text, ".?!\n", false)))
var bytes = TE_Util.file_size(t.file_path) var bytes = TE_Util.file_size(t.file_path)
r.add_constant_override("table_hseparation", int(r.rect_size.x / 5.0))
r.set_bbcode(r.table([ r.set_bbcode(r.table([
["chars", "words", "lines", "bytes"], ["chars", "words", "lines", "bytes"],
[chars, words, lines, bytes] [chars, words, lines, bytes]
@ -71,23 +68,6 @@ func get_symbols(t:String) -> Dictionary:
symbols = {} symbols = {}
return symbols return symbols
#func get_symbol_names(s:Dictionary):
# var out = []
# for k in s:
# if k != -1:
# out.append(s[k].name)
# return out
func get_tag_counts(s:Dictionary) -> Dictionary:
var out = {}
for k in s:
for tag in s[k].tags:
if not tag in out:
out[tag] = 1
else:
out[tag] += 1
return out
func apply_colors(e, t:TextEdit): func apply_colors(e, t:TextEdit):
t.add_color_override("font_color", e.color_text) t.add_color_override("font_color", e.color_text)
t.add_color_override("number_color", e.color_var) t.add_color_override("number_color", e.color_var)

View File

@ -1,7 +1,7 @@
tool tool
extends TE_ExtensionHelper extends TE_ExtensionHelper
func apply_colors(e:TE_Editor, t:TextEdit): func apply_colors(e:TextEditor, t:TextEdit):
.apply_colors(e, t) .apply_colors(e, t)
# symbols # symbols
t.add_color_region("[", "]", e.color_symbol, false) t.add_color_region("[", "]", e.color_symbol, false)
@ -27,7 +27,6 @@ func get_symbols(t:String) -> Dictionary:
# tags # tags
elif lines[i].begins_with(";") and "#" in lines[i]: elif lines[i].begins_with(";") and "#" in lines[i]:
for t in lines[i].substr(1).split("#"): for t in lines[i].substr(1).split("#"):
t = t.strip_edges()
if t: if t:
last.tags.append(t) last.tags.append(t)

View File

@ -17,32 +17,33 @@ func get_symbols(t:String):
var deep = max(0, len(lines[i]) - len(lines[i].strip_edges(true, false)) - 1) var deep = max(0, len(lines[i]) - len(lines[i].strip_edges(true, false)) - 1)
last = add_symbol(i, deep, key) last = add_symbol(i, deep, key)
# tags
# elif "/* #" in lines[i]:
# for tag in lines[i].split("/* #", true, 1)[1].split("*/", true, 1)[0].split("#"):
# tag = tag.strip_edges()
# if tag:
# last.tags.append(tag)
elif '"#": "' in lines[i]: elif '"#": "' in lines[i]:
for tag in lines[i].split('"#": "', true, 1)[1].split('"', true, 1)[0].split("#"): for tag in lines[i].split('"#": "', true, 1)[1].split('"', true, 1)[0].split("#"):
tag = tag.strip_edges() tag = tag.strip_edges()
if tag: if tag:
last.tags.append(tag) last.tags.append(tag)
elif '"tags": "' in lines[i]:
for tag in lines[i].split('"tags": "', true, 1)[1].split('"', true, 1)[0].split("#"):
tag = tag.strip_edges()
if tag:
last.tags.append(tag)
i += 1 i += 1
return out return out
func apply_colors(e:TE_Editor, t:TextEdit): func apply_colors(e:TextEditor, t:TextEdit):
.apply_colors(e, t) .apply_colors(e, t)
# vars # vars
t.add_color_region(' "', '"', e.color_varname) t.add_color_region(' "', '"', e.color_var)
t.add_color_region('"', '"', e.color_varname) t.add_color_region('"', '"', e.color_varname)
t.add_keyword_color("true", e.color_var) t.add_keyword_color("true", e.color_var)
t.add_keyword_color("false", e.color_var) t.add_keyword_color("false", e.color_var)
t.add_keyword_color("null", e.color_var) t.add_keyword_color("null", e.color_var)
# comments # comments
# t.add_color_region("/*", "*/", e.color_comment) t.add_color_region("/*", "*/", e.color_comment)
t.add_color_region('\t"#"', ",", e.color_comment, false) t.add_color_region("//", "", e.color_comment, true)

View File

@ -1,137 +1,16 @@
tool tool
extends TE_ExtensionHelper extends TE_ExtensionHelper
func generate_meta(t:TextEdit, r:RichTextLabel):
.generate_meta(t, r)
var i = 0
var meta = {}
var words = {}
var word_count = 0
var chaps = [{i=0, id="???", words={}, word_count=0 }]
while i < t.get_line_count():
var line = t.get_line(i)
# get meta
if i == 0 and line.begins_with("---"):
i += 1
while i < t.get_line_count() and not t.get_line(i).begins_with("---"):
if ":" in t.get_line(i):
var p = t.get_line(i).split(":", true, 1)
var k = p[0].strip_edges()
var v = p[1].strip_edges()
meta[k] = v
if k == "name":
chaps[-1].id = v
i += 1
# ignore comments
elif "<!--" in line:
pass
# ignore tables
elif "|" in line:
pass
# ignore code
elif line.begins_with("```") or line.begins_with("~~~"):
var head = line.substr(0, 3)
i += 1
while i < t.get_line_count() and not t.get_line(i).begins_with(head):
i += 1
# get chapter info
elif line.begins_with("#"):
var id = line.split(" ", true, 1)[1].strip_edges()
chaps.append({i=i, id=id, words={}, word_count=0 })
else:
var last = chaps[-1]
last.word_count += TE_Util.count_words(line, last.words)
i += 1
# total words
for chap in chaps:
word_count += chap.word_count
for word in chap.words:
if not word in words:
words[word] = chap.words[word]
else:
words[word] += chap.words[word]
# sort
TE_Util.sort_vals(chap.words)
r.push_align(RichTextLabel.ALIGN_CENTER)
r.push_table(4)
for x in ["#", "id", "word %s" % word_count, "words"]:
r.push_cell()
r.push_bold()
r.add_text(x)
r.pop()
r.pop()
var index:int = 0
for chap in chaps:
if chap.id == "???" and not chap.word_count:
continue
index += 1
r.push_cell()
r.push_color(Color.webgray)
r.add_text(str(index))
r.pop()
r.pop()
r.push_cell()
r.push_color(Color.webgray)
r.add_text(chap.id)
r.pop()
r.pop()
var div = 0 if not chap.word_count or not word_count else chap.word_count / float(word_count)
div *= 100.0
div = "%" + str(stepify(div, .1))
r.push_cell()
r.push_color(Color.webgray)
r.add_text(str(chap.word_count))
r.pop()
r.push_color(Color.gray)
r.add_text(" %s" % div)
r.pop()
r.pop()
r.push_cell()
r.push_color(Color.webgray)
r.add_text(PoolStringArray(chap.words.keys()).join(" "))
r.pop()
r.pop()
r.pop()
r.pop()
func _sort(a, b):
return a[1] > b[1]
func toggle_comment(t:TextEdit, head:String="<!-- ", tail:String=" -->"): func toggle_comment(t:TextEdit, head:String="<!-- ", tail:String=" -->"):
return .toggle_comment(t, head, tail) return .toggle_comment(t, head, tail)
func apply_colors(e:TE_Editor, t:TextEdit): func apply_colors(e:TextEditor, t:TextEdit):
.apply_colors(e, t) .apply_colors(e, t)
var code:Color = lerp(Color.white.darkened(.5), Color.deepskyblue, .333) var code:Color = lerp(e.color_text.darkened(.5), Color.yellowgreen, .5)
var quote:Color = lerp(e.color_text, e.color_symbol, .5)
t.add_color_override("function_color", e.color_text) t.add_keyword_color("true", e.color_var)
t.add_color_override("number_color", e.color_text) t.add_keyword_color("false", e.color_var)
# t.add_keyword_color("true", e.color_var)
# t.add_keyword_color("false", e.color_var)
# bold italic # bold italic
t.add_color_region("***", "***", Color.tomato.darkened(.3), false) t.add_color_region("***", "***", Color.tomato.darkened(.3), false)
@ -141,31 +20,24 @@ func apply_colors(e:TE_Editor, t:TextEdit):
t.add_color_region("*", "*", Color.tomato.lightened(.3), false) t.add_color_region("*", "*", Color.tomato.lightened(.3), false)
# quote # quote
t.add_color_region("> ", "", quote, true) t.add_color_region("> ", "", Color.white.darkened(.6), true)
# comment # comment
t.add_color_region("<!--", "-->", e.color_comment, false) t.add_color_region("<!--", "-->", e.color_comment, false)
# non official markdown:
# formatted
t.add_color_region("{", "}", lerp(e.color_text, e.color_var, .5).darkened(.25), false)
# t.add_color_region("[", "]", lerp(e.color_text, e.color_var, .5).darkened(.25), false)
# t.add_color_region("(", ")", lerp(e.color_text, e.color_var, .5).darkened(.25), false)
if false:
# quote
t.add_color_region('"', '"', quote, false)
# brackets
t.add_color_region('(', ')', quote, false)
else:
# url links
t.add_color_region("![", ")", e.color_var.lightened(.5))
# headings # headings
for i in range(1, 7): var head = e.color_symbol
var h = "#".repeat(i) t.add_color_region("# *", "*", head.darkened(.5), true)
t.add_color_region("%s *" % h, "*", e.get_symbol_color(i-1, -.33), true) t.add_color_region("# \"", "\"", head.lightened(.5), true)
t.add_color_region("%s \"" % h, "\"", e.get_symbol_color(i-1, .33), true) t.add_color_region("# ", "", head, true)
t.add_color_region("%s " % h, "*", e.get_symbol_color(i-1), true) t.add_color_region("## ", "", head, true)
t.add_color_region("### ", "", head, true)
t.add_color_region("#### ", "", head, true)
t.add_color_region("##### ", "", head, true)
t.add_color_region("###### ", "", head, true)
# url links
t.add_color_region("[", ")", e.color_var.lightened(.5))
# lists # lists
t.add_color_region("- [x", "]", Color.yellowgreen, false) t.add_color_region("- [x", "]", Color.yellowgreen, false)
@ -174,7 +46,6 @@ func apply_colors(e:TE_Editor, t:TextEdit):
# code blocks # code blocks
t.add_color_region("```", "```", code, false) t.add_color_region("```", "```", code, false)
t.add_color_region("~~~", "~~~", code, false) t.add_color_region("~~~", "~~~", code, false)
t.add_color_region("---", "---", code, false)
# strikeout # strikeout
t.add_color_region("~~", "~~", Color.tomato, false) t.add_color_region("~~", "~~", Color.tomato, false)
@ -185,9 +56,12 @@ func apply_colors(e:TE_Editor, t:TextEdit):
# at/mention # at/mention
t.add_color_region("@", " ", Color.yellowgreen, false) t.add_color_region("@", " ", Color.yellowgreen, false)
t.add_color_region(": ", "", e.color_text.lightened(.4), true)
# tables # tables
t.add_color_region("|", "", Color.tan, true) t.add_color_region("|", "", Color.tan, true)
func get_symbols(t:String) -> Dictionary: func get_symbols(t:String) -> Dictionary:
var out = .get_symbols(t) var out = .get_symbols(t)
var last = add_symbol() var last = add_symbol()
@ -195,33 +69,11 @@ func get_symbols(t:String) -> Dictionary:
var i = 0 var i = 0
while i < len(lines): while i < len(lines):
# initial meta data
if i == 0 and lines[i].begins_with("---"):
i += 1
while i < len(lines) and not lines[i].begins_with("---"):
if "tags: " in lines[i]:
for tag in lines[i].split("tags: ", true, 1)[1].split("#"):
tag = tag.strip_edges()
if tag:
last.tags.append(tag)
# elif "name: " in lines[i]:
# last.name = lines[i].split("name: ", true, 1)[1]
i += 1
# i += 1
elif lines[i].begins_with("```") or lines[i].begins_with("~~~"):
var head = lines[i].substr(0, 3)
i += 1
while i < len(lines) and not lines[i].begins_with(head):
i += 1
# symbols # symbols
elif lines[i].begins_with("#"): if lines[i].begins_with("#"):
var p = lines[i].split(" ", true, 1) var p = lines[i].split(" ", true, 1)
var deep = len(p[0])-1 var deep = len(p[0])-1
var name = "???" if len(p) == 1 else p[1].strip_edges() var name = p[1].strip_edges()
last = add_symbol(i, deep, name) last = add_symbol(i, deep, name)
# tags # tags

View File

@ -1,50 +0,0 @@
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

View File

@ -1,2 +0,0 @@
tool
extends TE_ExtensionHelper

View File

@ -1,9 +1,6 @@
tool tool
extends TE_ExtensionHelper extends TE_ExtensionHelper
func get_tab() -> String:
return " "
func _is_commented(lines) -> bool: func _is_commented(lines) -> bool:
for i in len(lines): for i in len(lines):
if not lines[i].strip_edges(): if not lines[i].strip_edges():
@ -46,7 +43,7 @@ func toggle_comment(t:TextEdit, head:String="", tail:String=""):
return [old, new] return [old, new]
func apply_colors(e:TE_Editor, t:TextEdit): func apply_colors(e:TextEditor, t:TextEdit):
.apply_colors(e, t) .apply_colors(e, t)
# strings # strings

View File

@ -5,8 +5,6 @@
[ext_resource path="res://addons/text_editor/fonts/unifont-13.0.01.ttf" type="DynamicFontData" id=3] [ext_resource path="res://addons/text_editor/fonts/unifont-13.0.01.ttf" type="DynamicFontData" id=3]
[resource] [resource]
size = 12
use_filter = true
font_data = ExtResource( 1 ) font_data = ExtResource( 1 )
fallback/0 = ExtResource( 3 ) fallback/0 = ExtResource( 3 )
fallback/1 = ExtResource( 2 ) fallback/1 = ExtResource( 2 )

View File

@ -5,8 +5,6 @@
[ext_resource path="res://addons/text_editor/fonts/unifont-13.0.01.ttf" type="DynamicFontData" id=3] [ext_resource path="res://addons/text_editor/fonts/unifont-13.0.01.ttf" type="DynamicFontData" id=3]
[resource] [resource]
size = 12
use_filter = true
font_data = ExtResource( 1 ) font_data = ExtResource( 1 )
fallback/0 = ExtResource( 3 ) fallback/0 = ExtResource( 3 )
fallback/1 = ExtResource( 2 ) fallback/1 = ExtResource( 2 )

View File

@ -5,8 +5,6 @@
[ext_resource path="res://addons/text_editor/fonts/unifont-13.0.01.ttf" type="DynamicFontData" id=3] [ext_resource path="res://addons/text_editor/fonts/unifont-13.0.01.ttf" type="DynamicFontData" id=3]
[resource] [resource]
size = 12
use_filter = true
font_data = ExtResource( 1 ) font_data = ExtResource( 1 )
fallback/0 = ExtResource( 3 ) fallback/0 = ExtResource( 3 )
fallback/1 = ExtResource( 2 ) fallback/1 = ExtResource( 2 )

View File

@ -5,8 +5,6 @@
[ext_resource path="res://addons/text_editor/fonts/unifont-13.0.01.ttf" type="DynamicFontData" id=3] [ext_resource path="res://addons/text_editor/fonts/unifont-13.0.01.ttf" type="DynamicFontData" id=3]
[resource] [resource]
size = 12
use_filter = true
font_data = ExtResource( 1 ) font_data = ExtResource( 1 )
fallback/0 = ExtResource( 3 ) fallback/0 = ExtResource( 3 )
fallback/1 = ExtResource( 2 ) fallback/1 = ExtResource( 2 )

View File

@ -5,8 +5,6 @@
[ext_resource path="res://addons/text_editor/fonts/unifont-13.0.01.ttf" type="DynamicFontData" id=3] [ext_resource path="res://addons/text_editor/fonts/unifont-13.0.01.ttf" type="DynamicFontData" id=3]
[resource] [resource]
size = 12
use_filter = true
font_data = ExtResource( 1 ) font_data = ExtResource( 1 )
fallback/0 = ExtResource( 3 ) fallback/0 = ExtResource( 3 )
fallback/1 = ExtResource( 2 ) fallback/1 = ExtResource( 2 )

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

View File

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/icon_blue.png-4b6f1e67dbe59cc990b970ce70a743ca.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/text_editor/icons/icon_blue.png"
dest_files=[ "res://.import/icon_blue.png-4b6f1e67dbe59cc990b970ce70a743ca.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

View File

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/icon_green.png-01008ffea524815bdbefdafa2b021148.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/text_editor/icons/icon_green.png"
dest_files=[ "res://.import/icon_green.png-01008ffea524815bdbefdafa2b021148.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

View File

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/icon_red.png-68ce187cb535e9b040383f41e156a86c.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/text_editor/icons/icon_red.png"
dest_files=[ "res://.import/icon_red.png-68ce187cb535e9b040383f41e156a86c.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

View File

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/icon_yellow.png-4fd0044497c78a10c7a9305f6c12f846.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/text_editor/icons/icon_yellow.png"
dest_files=[ "res://.import/icon_yellow.png-4fd0044497c78a10c7a9305f6c12f846.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View File

@ -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.12" version="1.0"
script="plugin.gd" script="plugin.gd"

View File

@ -1,3 +0,0 @@
[gd_resource type="StyleBoxEmpty" format=2]
[resource]

View File

@ -1,3 +0,0 @@
[gd_resource type="AudioBusLayout" format=2]
[resource]