Compare commits

..

12 Commits
v1.4 ... main

Author SHA1 Message Date
teebarjunk
25d4f161cf 1.12 2022-02-03 07:34:34 -05:00
teebarjunk
4225903a92 1.11 2021-12-19 10:43:24 -05:00
teebarjunk
dfe30486d2 1.10 2021-11-27 05:35:18 -05:00
teebarjunk
40beef4690 1.9 2021-11-24 11:09:48 -05:00
teebarjunk
498fb79e89 1.8 2021-11-20 08:53:02 -05:00
teebarjunk
baeeb0a808 1.7 2021-10-24 11:28:40 -04:00
teebarjunk
06e8d176c4 1.7 2021-10-24 11:27:27 -04:00
teebarjunk
4f09def7ef 1.6 2021-10-23 00:00:42 -04:00
teebarjunk
96c064c2b9 1.6 2021-10-22 23:51:34 -04:00
teebarjunk
c8ce103df4 1.5 2021-10-18 19:52:40 -04:00
teebarjunk
5bcd5a47b0 1.5 2021-10-18 19:50:21 -04:00
teebarjunk
f2ae9db115 1.4.1 2021-10-18 15:29:57 -04:00
48 changed files with 2736 additions and 588 deletions

1
.gitignore vendored
View File

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

View File

@ -1,3 +1,119 @@
# 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 # 1.4
- Added `sys` info tab. - Added `sys` info tab.
- Added `console` info tab. (wip) - Added `console` info tab. (wip)

145
README.md
View File

@ -1,48 +1,62 @@
# Text Editor # Text Editor
Version `1.4` Version `1.12`
![](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
- Tabs with scroll - Multi file tab system.
- File filtering - File browser filtering.
- Highlighting for common file formats (`md` `json`...) - Highlighting for common formats (`md` `json` `ini`...)
- Tag filtering system - Tag [System](#mini-features-tags).
- File Management: - File Management:
- Creation - Creation.
- Renaming - Renaming.
- Recycling - Recycling.
- Auto save/load settings - Moving.
- Many little *Ease of life* functions: - Search files.
- Folder open/close - Image previews.
- Comment toggling for: - Auto save/load settings.
- `.md`: `<!-- -->` - Many little *Ease of Life* [features](#mini-features).
- `.json`: `/* */`
- `.ini`: `; `
- `.cfg`: `; `
- `.yaml`: `# `
# Controls # Controls
- `ctrl + W` Close file - `ctrl + N` New file.
- `ctrl + shift + W` Open last closed file - `ctrl + W` Close file.
- `ctrl + tab` Select next open file - `ctrl + shift + W` Open last closed file .
- `ctrl + shift + tab` Select last open file - `ctrl + tab` Select next open file.
- `ctrl + mouse wheel` Adjust font size - `ctrl + shift + tab` Select last open file.
- `ctrl + up` `ctrl + down` Move selected lines - `ctrl + mouse wheel` Adjust font size.
- `ctrl + /` Toggle line comments - `ctrl + shift + mouse wheel` Adjust ui font size.
- `ctrl + M` Toggle file meta info - `ctrl + up` & `ctrl + down` Move selected lines.
- `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
To make it easier to find stuff there is a *Symbol* viewer. *Symbols* are like *Table of Contents* for a file.
- `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"`
@ -59,10 +73,81 @@ This will then highlight *Files* and *Symbols* that have that tag.
# Todo # Todo
- [x] `1.1` Preserve folders open/close state. - [x] `1.1` Preserve folders open/close state.
- [x] `1.3` Search all files. - [x] `1.3` Search all files.
- [ ] Search file. - [x] `1.7` Search file.
- [ ] Find and replace. - [ ] Find and replace.
- [ ] Improve meta data based on format. - [x] `1.7` Improve meta data based on format.
- [x] `1.2` Recycle folders. - [x] `1.2` Recycle folders.
- [x] `1.2` Unrecylce. (Toggle `view/directories/.trash` and press green arrow. - [x] `1.2` Unrecylce. (Toggle `view/directories/.trash` and press green arrow.)
- [ ] JSON formatting. - [ ] JSON formatting.
- [ ] JSON error testing. - [ ] 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>

BIN
README/changes_hint_toc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
README/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 97 KiB

View File

@ -1,5 +1,9 @@
tool
extends "res://addons/text_editor/TE_RichTextLabel.gd" extends "res://addons/text_editor/TE_RichTextLabel.gd"
func _ready():
clear()
func msg(msg): func msg(msg):
append_bbcode(str(msg)) append_bbcode(str(msg))
newline() newline()

View File

@ -1,7 +1,7 @@
tool tool
extends RichTextLabel extends RichTextLabel
var editor:TE_TextEditor var editor:TE_Editor
var click_pos:Vector2 var click_pos:Vector2
func _init(text): func _init(text):

View File

@ -1,7 +1,7 @@
tool tool
extends TextEdit extends TextEdit
var editor:TE_TextEditor var editor:TE_Editor
var _hscroll:HScrollBar var _hscroll:HScrollBar
var _vscroll:VScrollBar var _vscroll:VScrollBar
@ -9,6 +9,7 @@ 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 = {}
@ -17,30 +18,130 @@ 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, "set", ["in_focus", true]) _e = connect("focus_entered", self, "_focus_entered")
_e = connect("focus_exited", self, "set", ["in_focus", false]) _e = connect("focus_exited", self, "_focus_exited")
_e = connect("mouse_entered", self, "set", ["mouse_inside", true])
_e = connect("mouse_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)
get_menu().add_font_override("font", editor.FONT) var popup = get_menu()
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:
@ -56,43 +157,96 @@ 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:
return { var state = {
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)
func _file_renamed(old_path:String, new_path:String): if "text" in state:
if old_path == file_path: if state.text.strip_edges():
file_path = new_path text = state.text
update_name() else:
update_colors() 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
if not visible or not in_focus: # custom tab system
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 InputEventMouseButton and not e.pressed:
_update_selected_line()
if e is InputEventMouseButton and not e.pressed and e.control: if e is InputEventMouseButton and not e.pressed and e.control:
var line:String = get_line(cursor_get_line()) var line:String = get_line(cursor_get_line())
# click link
var ca = line.find("(") var ca = line.find("(")
var cb = line.find_last(")") var cb = line.find_last(")")
if ca != -1 and cb != -1: if ca != -1 and cb != -1:
@ -105,29 +259,6 @@ func _input(e):
var link = file_path.get_base_dir().plus_file(file) var link = file_path.get_base_dir().plus_file(file)
editor.open_file(link) editor.open_file(link)
editor.select_file(link) editor.select_file(link)
# print(link)
if e is InputEventKey and e.pressed and e.control:
# tab to next
if e.scancode == KEY_TAB:
get_tree().set_input_as_handled()
if e.shift:
get_parent().prev()
else:
get_parent().next()
# save files
elif e.scancode == KEY_S:
get_tree().set_input_as_handled()
editor.save_files()
# close file
elif e.scancode == KEY_W:
get_tree().set_input_as_handled()
if e.shift:
editor.open_last_file()
else:
close()
# remember last selection # remember last selection
if e is InputEventKey and e.pressed: if e is InputEventKey and e.pressed:
@ -170,6 +301,30 @@ 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
@ -179,20 +334,35 @@ func _unhandled_key_input(e):
helper.toggle_comment(self) helper.toggle_comment(self)
get_tree().set_input_as_handled() get_tree().set_input_as_handled()
func _file_renamed(old_path:String, new_path:String):
if old_path == file_path:
file_path = new_path
update_name()
update_colors()
func _file_selected(p:String): func _file_selected(p:String):
if not p: if p != file_path:
return return
if p == file_path:
grab_focus()
grab_click_focus()
update_symbols() update_symbols()
update_heading() update_heading()
func goto_line(line:int): # 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 # force scroll to bottom so selected line will be at top
if bottom:
cursor_set_line(get_line_count()) cursor_set_line(get_line_count())
cursor_set_line(line) cursor_set_line(line)
_update_selected_line()
func text_changed(): func text_changed():
if last_selected: if last_selected:
@ -224,6 +394,8 @@ func set_temporary(t):
update_name() update_name()
func update_symbols(): func update_symbols():
update_helper()
symbols.clear() symbols.clear()
tags.clear() tags.clear()
@ -239,38 +411,56 @@ 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", ["close"], CONNECT_ONESHOT) _e = editor.popup_unsaved.connect("confirmed", self, "_popup", ["confirm_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:
"close": "confirm_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
text = TE_Util.load_text(path) if path != "":
update_name() text = editor.load_file(path)
clear_undo_history()
update_colors() update_colors()
update_name()
func update_colors(): func update_helper():
clear_colors()
helper = editor.get_extension_helper(file_path) helper = editor.get_extension_helper(file_path)
helper.apply_colors(editor, self) helper.apply_colors(editor, self)
func update_colors():
clear_colors()
update_helper()
func _created_nonexisting(fp:String):
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(editor.current_directory):
var err_msg = "can't save to %s" % file_path var err_msg = "can't save to %s" % file_path
@ -284,12 +474,35 @@ func save_file():
update_symbols() update_symbols()
func update_name(): func update_name():
var n = file_path.get_file().split(".", true, 1)[0] var n:String
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)
update_heading() name = n
func update_heading(): func update_heading():
if Engine.editor_hint: if Engine.editor_hint:
@ -306,5 +519,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) return modified or (not File.new().file_exists(file_path) and text)

View File

@ -0,0 +1,101 @@
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,7 +1,9 @@
extends TabContainer extends TabContainer
onready var editor:TE_TextEditor = owner onready var editor:TE_Editor = 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(): if not editor.is_plugin_active():
@ -10,9 +12,72 @@ func _ready():
var _e var _e
_e = connect("mouse_entered", self, "set", ["mouse", true]) _e = connect("mouse_entered", self, "set", ["mouse", true])
_e = connect("mouse_exited", self, "set", ["mouse", false]) _e = connect("mouse_exited", self, "set", ["mouse", false])
_e = connect("tab_changed", self, "_tab_changed")
_e = connect("pre_popup_pressed", self, "update_popup")
add_font_override("font", editor.FONT_R) 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():
return return
@ -26,6 +91,14 @@ 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

@ -7,6 +7,8 @@ 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 filter:String = ""
var selected:Array = [] var selected:Array = []
var dragging:Array = [] var dragging:Array = []
var drag_start:Vector2 var drag_start:Vector2
@ -20,6 +22,10 @@ func _ready():
_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")
var le:LineEdit = get_node(p_filter)
_e = le.connect("text_changed", self, "_filter_changed")
le.add_font_override("font", editor.FONT_R)
# file popup # file popup
file_popup.clear() file_popup.clear()
file_popup.rect_size = Vector2.ZERO file_popup.rect_size = Vector2.ZERO
@ -33,9 +39,14 @@ func _ready():
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_item("New Folder")
dir_popup.add_separator() dir_popup.add_separator()
dir_popup.add_item("Remove") 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", editor.FONT)
@ -44,6 +55,10 @@ func _ready():
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 type = selected[0]
var file = selected[1] var file = selected[1]
@ -51,9 +66,32 @@ func _dir_popup(index:int):
file = file.file_path file = file.file_path
match dir_popup.get_item_text(index): match dir_popup.get_item_text(index):
"New File": editor.popup_create_file(file) "New File":
"New Folder": editor.popup_create_dir(file) editor.popup_create_file(file)
"Remove": editor.recycle(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 type = selected[0]
@ -70,7 +108,7 @@ func _file_popup(index:int):
"Remove": "Remove":
if type == "f": if type == "f":
editor.recycle(file) editor.recycle(file, true)
_: _:
selected = [] selected = []
@ -95,14 +133,21 @@ func _input(e:InputEvent):
var file = meta_hovered[1] var file = meta_hovered[1]
if e.button_index == BUTTON_LEFT: if e.button_index == BUTTON_LEFT:
if e.pressed: if e.pressed:
if type in ["f", "d"]: if type in ["f", "d"]:
if type == "f" and Input.is_key_pressed(KEY_CONTROL):
editor.file_data[file].open = not editor.file_data[file].open
_redraw()
else:
var file_path = file if type == "f" else file.file_path var file_path = file if type == "f" else file.file_path
if file_path.begins_with(editor.PATH_TRASH): # can't move recycling
return # can't move recycling if editor.is_trash_path(file_path):
return
# select for drag
else: else:
dragging = meta_hovered dragging = meta_hovered
@ -110,14 +155,19 @@ func _input(e:InputEvent):
drag_label.editor = editor drag_label.editor = editor
editor.add_child(drag_label) editor.add_child(drag_label)
else:
if type == "f" and Input.is_key_pressed(KEY_CONTROL):
pass
else: else:
if dragging and dragging != meta_hovered: if dragging and dragging != meta_hovered:
var drag_type = dragging[0] var drag_type = dragging[0]
var drag_file = dragging[1] var drag_file = dragging[1]
# dragged onto directory?
if type == "d": if type == "d":
var dir:String = file.file_path var dir:String = file.file_path
var old_path:String = drag_file 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)
@ -132,12 +182,19 @@ func _input(e:InputEvent):
# unrecycle # unrecycle
"unrecycle": "unrecycle":
editor.unrecycle(file) 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:
@ -162,69 +219,139 @@ var lines:PoolStringArray = PoolStringArray()
func _redraw(): func _redraw():
lines = PoolStringArray() lines = PoolStringArray()
_draw_dir(editor.file_list[""], 0) lines.append_array(_draw_dir(editor.file_list[""], 0))
set_bbcode(lines.join("\n")) set_bbcode(lines.join("\n"))
const FOLDER:String = "🗀" # not visible in godot func _dull_nonwords(s:String, clr:Color, dull:Color) -> String:
func _draw_dir(dir:Dictionary, deep:int): var on = false
var parts = []
for c in 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_OPEN:String = "🗁" # not visible in Godot.
func _draw_dir(dir:Dictionary, deep:int) -> Array:
var is_tagging = editor.is_tagging() var is_tagging = editor.is_tagging()
var dimmest:float = .5 if is_tagging else 0.0 var dimmest:float = .5 if is_tagging else 0.0
var tint = editor.get_tint_color(dir.tint)
var dull = Color.white.darkened(.65)
var dull_tint = tint.darkened(.5)
var space = clr("".repeat(deep), Color.white.darkened(.8)) var space = ""
var file:String = dir.file_path var file:String = dir.file_path
var head:String = "" if dir.open else ""
head = clr(space+FOLDER+head, Color.white.darkened(.5))
head += " " + b(file.get_file())
var link:String = meta(head, ["d", dir], file)
if file.begins_with(editor.PATH_TRASH) and file.count("/") == 3:
link += " " + meta(clr("", Color.yellowgreen), ["unrecycle", dir], file)
lines.append(clr(link, Color.white.darkened(dimmest)))
space = clr("".repeat(deep), Color.white.darkened(.8))
var head:String = "" if dir.open else ""
var fold:String = FOLDER_OPEN if dir.open else FOLDER_CLOSED
var dname = b(_dull_nonwords(file.get_file(), tint.darkened(0 if editor.is_dir_tagged(dir) else 0.5), dull))
dname = clr("", dull) + dname + clr("", dull)
head = clr(space+fold, Color.gold) + clr(head, Color.white.darkened(.5))
head += " %s" % dname
var link:String = meta(head, ["d", dir], editor.get_localized_path(file))
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: if dir.open or filter:
# draw dirs # draw dirs
for path in dir.dirs: for path in dir.dirs:
var file_path = dir.all[path] var file_path = dir.all[path]
if file_path is Dictionary and file_path.show: if file_path is Dictionary and (file_path.show or filter):
_draw_dir(file_path, deep+1) out.append_array(_draw_dir(file_path, deep+1))
# draw files # draw files
var last = len(dir.files)-1 var last = len(dir.files)-1
for i in len(dir.files): for i in len(dir.files):
var file_path = dir.files[i] var file_path = dir.files[i]
file = file_path.get_file() var fname = file_path.get_file()
var p = file.split(".", true, 1) file = fname
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 = Color.white var color = tint
head = "┣╸" if i != last else "┗╸" head = "" if filter else "┣╸" if i != last else "┗╸"
if "readme" in file.to_lower(): var fname_lower = fname.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):
file = b(file) bold = true
else: else:
color = color.darkened(dimmest) color = color.darkened(dimmest)
else: else:
pass pass
file = clr(file, color) file = _dull_nonwords(file, color, dull)
ext = clr("." + ext, Color.white.darkened(.65))
var line = space + head + file + ext if bold:
lines.append(meta(line, ["f", file_path], file_path)) file = b(file)
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_TextEditor = owner onready var editor:TE_Editor = owner
var fr:FuncRef var fr:FuncRef
func _ready(): func _ready():
@ -33,6 +33,5 @@ func _lost_focus():
func _enter(t:String): func _enter(t:String):
if fr: if fr:
print("calling %s with %s" % [fr, t])
fr.call_func(t) fr.call_func(t)
hide() hide()

View File

@ -17,6 +17,9 @@ 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,19 +1,39 @@
tool tool
extends TabContainer extends TabContainer
onready var editor:TE_TextEditor = owner onready var editor:TE_Editor = owner
func _ready(): func _ready():
if not editor.is_plugin_active(): if not editor.is_plugin_active():
return return
set_visible(false)
add_font_override("font", editor.FONT_R) add_font_override("font", editor.FONT_R)
func _unhandled_key_input(e): func _unhandled_key_input(e):
if not editor.is_plugin_active(): if not editor.is_plugin_active():
return return
# Ctrl + M = meta tabs if e.control and e.pressed:
if e.scancode == KEY_M and e.control and e.pressed: match e.scancode:
visible = not visible # show this menu
KEY_M:
set_visible(not get_parent().visible)
get_tree().set_input_as_handled() 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,6 +1,6 @@
extends RichTextLabel extends RichTextLabel
onready var editor:TE_TextEditor = owner onready var editor:TE_Editor = owner
var meta_items:Array = [] var meta_items:Array = []
var meta_hovered:Array = [] var meta_hovered:Array = []
@ -97,6 +97,7 @@ func table(rows) -> String:
func b(t:String) -> String: return "[b]%s[/b]" % t func b(t:String) -> String: return "[b]%s[/b]" % t
func i(t:String) -> String: return "[i]%s[/i]" % 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 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 center(t:String): return "[center]%s[/center]" % t

View File

@ -3,44 +3,97 @@ extends "res://addons/text_editor/TE_RichTextLabel.gd"
var chapter_info:Array = [] var chapter_info:Array = []
var sort_on:String = "words" var sort_on:String = "words"
var sort_reverse:Dictionary = { id=false, words=false, unique=false } 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(): func _ready():
var _e var btn = get_parent().get_node("update")
_e = editor.connect("file_opened", self, "_update") btn.add_font_override("font", editor.FONT_R)
_e = editor.connect("file_saved", self, "_update")
func _update(f): var _e = btn.connect("pressed", self, "_update")
set_process(true)
func _process(_delta): func _update():
chapter_info.clear() 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: for path in editor.file_paths:
var file = path.get_file() var file = path.get_file()
var ext = file.get_extension() var ext = file.get_extension()
match ext: match ext:
"md": _process_md(path) "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() _sort()
_redraw() _redraw()
set_process(false) const WEEKDAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
const MONTHS = ["Januaray", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
func _chapter(path:String, line:int, id:String): const TIMES:Dictionary = {
chapter_info.append({ path=path, line=line, id=id, words=0, chars=0, unique=0 }) "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): func _process_md(path:String):
var lines = TE_Util.load_text(path).split("\n") var lines = TE_Util.load_text(path).split("\n")
_chapter(path, 0, "NOH") 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 var i = 0
while i < len(lines): while i < len(lines):
# skip head meta # skip head meta
if i == 0 and lines[i].begins_with("---"): if i == 0 and lines[i].begins_with("---"):
i += 1 i += 1
while i < len(lines) and not lines[i].begins_with("---"): 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 i += 1
# skip comments
elif "<!--" in lines[i]:
pass
# skip code blocks # skip code blocks
elif lines[i].begins_with("~~~") or lines[i].begins_with("```"): elif lines[i].begins_with("~~~") or lines[i].begins_with("```"):
var head = lines[i].substr(0, 3) var head = lines[i].substr(0, 3)
@ -51,28 +104,32 @@ func _process_md(path:String):
# heading # heading
elif lines[i].begins_with("#"): elif lines[i].begins_with("#"):
var p = lines[i].split(" ", true, 1) var p = lines[i].split(" ", true, 1)
var id = lines[i].split(" ", true, 1)[1].strip_edges() var id = lines[i].split(" ", true, 1)
_chapter(path, i, id) var deep = len(id[0])
id = "???" if len(id) == 1 else id[1].strip_edges()
out.chaps += 1
else: else:
var words = lines[i].split(" ", false) out.words += TE_Util.count_words(lines[i], out.uwords, skip_words)
var unique = []
for word in words:
var w = clean_word(word.to_lower())
if w and not w in unique:
unique.append(w)
chapter_info[-1].words += len(words)
chapter_info[-1].unique += len(unique)
i += 1 i += 1
func clean_word(w:String): # sort word counts
var out = "" TE_Util.sort_vals(out.uwords)
for c in w: var words = PoolStringArray(out.uwords.keys())
if c in "abcdefghijklmnopqrstuvwxyz": var words_top = words
out += c if len(words_top) > 16:
return out 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): func _clicked(args):
match args[0]: match args[0]:
@ -80,6 +137,7 @@ func _clicked(args):
var key = args[1] var key = args[1]
if sort_on != key: if sort_on != key:
sort_on = key sort_on = key
sort_on_index = sort_reverse.keys().find(sort_on)
else: else:
sort_reverse[key] = not sort_reverse[key] sort_reverse[key] = not sort_reverse[key]
@ -87,35 +145,46 @@ func _clicked(args):
_redraw() _redraw()
"goto": "goto":
print(args)
var tab = editor.open_file(args[1]) var tab = editor.open_file(args[1])
editor.select_file(args[1]) editor.select_file(args[1])
tab.goto_line(args[2]) tab.goto_line(args[2])
func _sort(): func _sort():
if sort_reverse[sort_on]: if sort_reverse[sort_on]:
chapter_info.sort_custom(self, "_sort_chapters")
else:
chapter_info.sort_custom(self, "_sort_chapters_r") 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(a, b):
func _sort_chapters_r(a, b): return a[sort_on] >= b[sort_on] return a[sort_on] < b[sort_on]
func _sort_chapters_r(a, b):
return a[sort_on] > b[sort_on]
func _redraw(): func _redraw():
clear() clear()
var c1 = Color.white.darkened(.4) var c1 = Color.white.darkened(.4)
var c2 = Color.white.darkened(.3) 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_align(RichTextLabel.ALIGN_CENTER)
push_table(3) push_table(len(cols))
for id in ["id", "words", "unique"]: add_constant_override("table_hseparation", 8)
for id in cols:
push_cell() push_cell()
push_bold() push_bold()
push_meta(add_meta(["sort_table", id], "sort on %s" % id)) push_meta(add_meta(["sort_table", id], "sort on %s" % id))
add_text(id) add_text(id)
if sort_on == id: if sort_on == id:
push_color(Color.white.darkened(.5)) 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 "") add_text("" if sort_reverse[id] else "")
pop() pop()
pop() pop()
@ -124,26 +193,50 @@ func _redraw():
for i in len(chapter_info): for i in len(chapter_info):
var item = chapter_info[i] var item = chapter_info[i]
if item.id == "NOH" and not item.words:
continue
var clr = c1 if i%2==0 else c2 var clr = c1 if i%2==0 else c2
var clrh = ch1 if i%2==0 else ch2
# id # id
push_cell() push_cell()
push_color(clr) push_color(clrh if sort_on_index == 0 else clr)
push_meta(add_meta(["goto", item.path, item.line], item.path)) push_meta(add_meta(["goto", item.path, item.line], item.path + "\n" + item.uwords_all))
add_text(item.id) add_text(item.id)
pop() pop()
pop() pop()
pop() pop()
# word cound # chapters
for w in ["words", "unique"]:
push_cell() push_cell()
push_color(clr) push_color(clrh if sort_on_index == 1 else clr)
add_text(TE_Util.commas(item[w])) 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,7 +1,9 @@
tool tool
extends "res://addons/text_editor/TE_RichTextLabel.gd" extends "res://addons/text_editor/TE_RichTextLabel.gd"
onready var line_edit:LineEdit = get_parent().get_node("le") 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 console_urls:Array = []
var last_search:String = "" var last_search:String = ""
@ -10,26 +12,33 @@ func _ready():
var _e var _e
_e = line_edit.connect("text_entered", self, "_text_entered") _e = line_edit.connect("text_entered", self, "_text_entered")
# fix fonts
line_edit.add_font_override("font", editor.FONT_R) 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 _unhandled_key_input(e): func select():
if not editor.is_plugin_active():
return
# Ctrl + F to search
if e.scancode == KEY_F and e.pressed and e.control:
line_edit.grab_focus() line_edit.grab_focus()
line_edit.grab_click_focus() line_edit.grab_click_focus()
get_parent().get_parent().show() line_edit.select_all()
get_parent().get_parent().current_tab = get_index()
get_tree().set_input_as_handled()
func _clicked(args): func _clicked(args):
match args[0]: match args[0]:
"goto": "goto":
var tab = editor.open_file(args[1]) var tab:TextEdit = editor.open_file(args[1])
editor.select_file(args[1]) editor.select_file(args[1])
tab.goto_line(int(args[2])) 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): func _text_entered(search_for:String):
last_search = search_for last_search = search_for
@ -44,61 +53,111 @@ func _text_entered(search_for:String):
var file_path:String = fpaths[k] var file_path:String = fpaths[k]
var l = clr("%s/%s " % [k+1, len(fpaths)], Color.orange) + clr(file_path.get_file(), Color.yellow) 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], file_path) l = meta(l, ["goto", file_path, 0, 0, 0], file_path)
bbcode.append(l) bbcode.append(l)
for j in len(found[file_path]): var all_found = found[file_path]
for j in len(all_found):
var result = found[file_path][j] var result = found[file_path][j]
var got_lines = result[0] var got_lines = result[0]
var line_index = result[1] var highlight_from = result[1]
var char_index = result[2] var line_index = result[2]
var char_index = result[3]
if j != 0: bbcode.append(clr(" %s/%s" % [j+1, len(all_found)], Color.orange))
bbcode.append("\t" + clr("...", Color.gray))
for i in len(got_lines): for i in len(got_lines):
l = "" l = ""
var highlight = got_lines[i][0]
var lindex = got_lines[i][1]
var ltext = got_lines[i][2]
if i == 2: if highlight:
var line:String = got_lines[i] # var line:String = ltext
var head:String = line.substr(0, char_index) # var head:String = line.substr(0, char_index)
var midd:String = line.substr(char_index, len(search_for)+1) # var midd:String = line.substr(char_index, len(search_for))
var tail:String = line.substr(char_index+len(search_for)+1) # var tail:String = line.substr(char_index+len(search_for))
head = clr(head, Color.tomato.lightened(.5)) # head = clr(head, Color.white.darkened(.25))
midd = clr(midd, Color.tomato.darkened(.25)) # midd = b(clr(midd, Color.white))
tail = clr(tail, Color.tomato.lightened(.5)) # tail = clr(tail, Color.white.darkened(.25))
l = "\t" + clr(str(line_index-2+i+1) + ": ", Color.tomato.lightened(.5)) + (head+midd+tail)
elif line_index-2+i >= 0: var h = TE_Util.highlight(ltext, char_index, len(search_for), Color.white.darkened(.25), Color.white)
l = "\t" + clr(str(line_index-2+i+1) + ": ", Color.gray) + got_lines[i]
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: if l:
l = meta(l, ["goto", file_path, line_index]) l = meta(l, ["goto", file_path, highlight_from, line_index, char_index, len(search_for)])
bbcode.append(l) bbcode.append(l)
set_bbcode(bbcode.join("\n")) set_bbcode(bbcode.join("\n"))
# get a list of files containging lines # get a list of files containging lines
func _search(search_for:String) -> Dictionary: func _search(search_for:String) -> Dictionary:
var found = {} var out = {}
var search_for_l = search_for.to_lower() # lowercase. TODO: match case var search_for_l:String
for path in editor.file_paths:
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") var lines = TE_Util.load_text(path).split("\n")
for line_index in len(lines): for line_index in len(lines):
var line:String = lines[line_index].to_lower() 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 # find index where result is found
var char_index:int = line.find(search_for_l) var char_index:int = line.find(search_for_l)
if char_index != -1: if char_index != -1:
if not path in found: if not path in out:
found[path] = [] out[path] = []
var preview_lines = PoolStringArray()
var preview_lines = [[true, line_index, lines[line_index]]]
var highlight_from:int = line_index var highlight_from:int = line_index
# show surrounding 5 lines.
for i in range(-2, 3): # previous few lines before a blank
if line_index+i >= 0 and line_index+i < len(lines): for i in range(1, 3):
preview_lines.append(lines[line_index+i]) if line_index-i >= 0:
else: if not lines[line_index-i].strip_edges():
preview_lines.append("") 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 # lines, index in file, index in line
found[path].append([preview_lines, line_index, char_index]) out[path].append([preview_lines, highlight_from, line_index, char_index])
return found
return out

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,26 @@
tool tool
extends "res://addons/text_editor/TE_RichTextLabel.gd" extends "res://addons/text_editor/TE_RichTextLabel.gd"
var hscrolls:Dictionary = {}
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 = 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)
@ -13,8 +29,61 @@ func _ready():
call_deferred("_redraw") call_deferred("_redraw")
func _filter_changed(t:String):
filter = t.to_lower()
_redraw()
func _selected_symbol_line(line:int):
selected_line = clamp(line, 0, get_line_count())
scroll_to_line(clamp(line-1, 0, get_line_count()-1))
_redraw()
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): func _clicked(args:Array):
var te:TextEdit = editor.get_selected_tab() var te:TextEdit = editor.get_selected_tab()
# select entire symbol block?
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]) te.goto_line(args[1])
func _redraw(): func _redraw():
@ -37,22 +106,37 @@ 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 deep = symbol_info.deep
var space = "" if not deep else clr("-".repeat(deep), Color.white.darkened(.75)) var space = "" if not deep else clr("-".repeat(deep), Color.white.darkened(.75))
var cl = Color.deepskyblue if deep == 0 else Color.white var cl = Color.white
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): if not editor.is_tagged_or_visible(symbol_info.tags):
cl = cl.darkened(.7) cl = cl.darkened(.7)
elif deep >= 1:
cl = cl.darkened(.33 * (deep-1))
var tags = "" if not symbol_info.tags else PoolStringArray(symbol_info.tags).join(", ") var tags = "" if not symbol_info.tags else PoolStringArray(symbol_info.tags).join(", ")
t.append(clr(meta(space + symbol_info.name, [symbol_info, line_index], tags), cl)) 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_TextEditor = owner onready var editor:TE_Editor = owner
var mouse_over:bool = false var mouse_over:bool = false

View File

@ -16,40 +16,37 @@ func _ready():
theme.set_font("font", "TooltipLabel", editor.FONT_R) theme.set_font("font", "TooltipLabel", editor.FONT_R)
call_deferred("_redraw") call_deferred("_redraw")
#
#func _hovered(index):
# var tag = tag_indices[int(index)]
# var count = editor.tag_counts[tag]
# hint_tooltip =
#func _unhover(t):
# hint_tooltip = ""
func _clicked(args:Array): func _clicked(args:Array):
var tag = args[0] var tag = args[0]
editor.enable_tag(tag, not editor.is_tag_enabled(tag)) var was_enabled = editor.is_tag_enabled(tag)
func sort_tags(tags:Dictionary): if not Input.is_key_pressed(KEY_CONTROL):
var sorter:Array = [] editor.tags_enabled.clear()
for tag in tags:
sorter.append([tag, tags[tag]])
sorter.sort_custom(self, "_sort_tags") editor.enable_tag(tag, not was_enabled)
tags.clear() #func sort_tags(tags:Dictionary):
for item in sorter: # var sorter:Array = []
tags[item[0]] = item[1] # for tag in tags:
return tags # sorter.append([tag, tags[tag]])
#
func _sort_tags(a, b): # sorter.sort_custom(self, "_sort_tags")
return a[0] < b[0] #
# tags.clear()
# for item in sorter:
# tags[item[0]] = item[1]
# return tags
#
#func _sort_tags(a, b):
# return a[0] < b[0]
func _redraw(): func _redraw():
var tab = editor.get_selected_tab() var tab = editor.get_selected_tab()
var tags = editor.tag_counts var tags = editor.tags
var tab_tags = {} if not tab else tab.tags var tab_tags = {} if not tab else tab.tags
sort_tags(tags) # sort_tags(tags)
if not tags: if not tags:
set_bbcode("[color=#%s][i][center]*No tags*" % [Color.webgray.to_html()]) set_bbcode("[color=#%s][i][center]*No tags*" % [Color.webgray.to_html()])
@ -59,7 +56,7 @@ 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.tag_counts[tag] var count = editor.tags[tag]
var enabled = editor.is_tag_enabled(tag) var enabled = editor.is_tag_enabled(tag)
var x = tag var x = tag

View File

@ -1,5 +1,77 @@
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):
@ -21,6 +93,16 @@ 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)
@ -57,23 +139,55 @@ 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)
static func dig(d, obj:Object, fname:String): const _dig = {depth=0}
var f = funcref(obj, fname)
if d is Dictionary:
_dig_dict(d, f)
elif d is Node:
_dig_node(d, f)
static func _dig_dict(d:Dictionary, f:FuncRef): 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):
var f:FuncRef = funcref(obj, fname)
var depth:int = 0
if d is Dictionary:
_dig_dict(d, f, depth)
elif d is Node:
_dig_node(d, f, depth)
static func _dig_dict(d:Dictionary, f:FuncRef, depth:int):
_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) _dig_dict(d[k], f, depth+1)
static func _dig_node(d:Node, f:FuncRef): static func _dig_node(d:Node, f:FuncRef, depth:int):
_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) _dig_node(d.get_child(i), f, depth+1)
static func file_size(path:String) -> String: static func file_size(path:String) -> String:
var f:File = File.new() var f:File = File.new()
@ -86,6 +200,21 @@ static func file_size(path:String) -> String:
static func hue_shift(c:Color, h:float) -> Color: static func hue_shift(c:Color, h:float) -> Color:
return c.from_hsv(wrapf(c.h + h, 0.0, 1.0), c.s, c.v, c.a) return c.from_hsv(wrapf(c.h + h, 0.0, 1.0), c.s, c.v, c.a)
static func highlight(line:String, start:int, length:int, default_color:Color, highlight_color:Color) -> String:
var head:String = line.substr(0, start)
var midd:String = line.substr(start, length)
var tail:String = line.substr(start + length)
head = clr(head, default_color)
midd = b(clr(midd, highlight_color))
tail = clr(tail, default_color)
return head + midd + tail
static func b(t:String) -> String: return "[b]%s[/b]" % t
static func clr(t:String, c:Color) -> String: return "[color=#%s]%s[/color]" % [c.to_html(), t]
#static func saturate(c:Color, s:float=1.0, v:float=1.0) -> Color:
# 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,7 @@
[gd_scene load_steps=24 format=2] [gd_scene load_steps=29 format=2]
[ext_resource path="res://addons/text_editor/TE_Console.gd" type="Script" id=1] [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]
@ -17,26 +17,34 @@
[ext_resource path="res://addons/text_editor/TE_Search.gd" type="Script" id=15] [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_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_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=1] [sub_resource type="Theme" id=8]
[sub_resource type="Theme" id=9]
TooltipLabel/fonts/font = ExtResource( 12 ) TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=2] [sub_resource type="Theme" id=10]
TooltipLabel/fonts/font = ExtResource( 12 ) TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=3] [sub_resource type="Theme" id=11]
TooltipLabel/fonts/font = ExtResource( 12 ) TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=4] [sub_resource type="Theme" id=12]
TooltipLabel/fonts/font = ExtResource( 12 ) TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=5] [sub_resource type="Theme" id=13]
TooltipLabel/fonts/font = ExtResource( 12 ) TooltipLabel/fonts/font = ExtResource( 12 )
[sub_resource type="Theme" id=6] [sub_resource type="Theme" id=14]
TooltipLabel/fonts/font = ExtResource( 12 ) TooltipLabel/fonts/font = ExtResource( 12 )
[node name="text_editor" type="Control"] [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
@ -45,6 +53,13 @@ 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
@ -56,6 +71,7 @@ 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
@ -63,6 +79,7 @@ show_line_numbers = true
draw_tabs = true draw_tabs = true
fold_gutter = true fold_gutter = true
highlight_all_occurrences = true highlight_all_occurrences = true
hiding_enabled = true
minimap_draw = true minimap_draw = true
script = ExtResource( 4 ) script = ExtResource( 4 )
@ -76,33 +93,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 = 34.0 margin_bottom = 38.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 = 27.0 margin_bottom = 31.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 = 20.0 margin_bottom = 24.0
text = "⟳" text = "⟳"
[node name="file_button" type="MenuButton" parent="c/c/c"] [node name="file" type="MenuButton" parent="c/c/c"]
margin_left = 16.0 margin_left = 16.0
margin_right = 48.0 margin_right = 48.0
margin_bottom = 20.0 margin_bottom = 24.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_button" type="MenuButton" parent="c/c/c"] [node name="view" type="MenuButton" parent="c/c/c"]
margin_left = 52.0 margin_left = 52.0
margin_right = 93.0 margin_right = 93.0
margin_bottom = 20.0 margin_bottom = 24.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 ]
@ -110,8 +127,56 @@ __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 = 34.0 margin_top = 38.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
@ -122,7 +187,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 = 566.0 margin_bottom = 562.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
@ -131,16 +196,31 @@ 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 = 559.0 margin_bottom = 555.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
[node name="list_files" type="RichTextLabel" parent="c/div1/c2/c"] [node name="c" type="VBoxContainer" 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( 1 ) theme = SubResource( 9 )
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 )
@ -151,23 +231,24 @@ 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/list_files"] [node name="file_popup" type="PopupMenu" parent="c/div1/c2/c/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/list_files"] [node name="dir_popup" type="PopupMenu" parent="c/div1/c2/c/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, "New Folder", null, 0, false, false, 1, 0, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Remove", null, 0, false, false, 3, 0, null, "", false ] 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 ]
[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 = 566.0 margin_bottom = 562.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
split_offset = -80 split_offset = -80
@ -177,7 +258,7 @@ __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 = 566.0 margin_bottom = 562.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
@ -190,16 +271,24 @@ script = ExtResource( 8 )
[node name="c" type="VSplitContainer" parent="c/div1/div2/c"] [node name="c" type="VSplitContainer" parent="c/div1/div2/c"]
margin_right = 614.0 margin_right = 614.0
margin_bottom = 566.0 margin_bottom = 562.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
split_offset = -200 split_offset = 100
[node name="tab_container" type="TabContainer" parent="c/div1/div2/c/c"] [node name="c2" type="VBoxContainer" parent="c/div1/div2/c/c"]
margin_right = 614.0 margin_right = 614.0
margin_bottom = 566.0 margin_bottom = 375.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 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
@ -208,28 +297,78 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="meta_tabs" type="TabContainer" parent="c/div1/div2/c/c"] [node name="c" type="HBoxContainer" parent="c/div1/div2/c/c/c2"]
visible = false margin_top = 357.0
margin_top = 288.0
margin_right = 614.0 margin_right = 614.0
margin_bottom = 566.0 margin_bottom = 375.0
script = ExtResource( 16 ) size_flags_horizontal = 3
script = ExtResource( 18 )
[node name="console" type="RichTextLabel" parent="c/div1/div2/c/c/meta_tabs"] [node name="l" type="RichTextLabel" parent="c/div1/div2/c/c/c2/c"]
anchor_right = 1.0 margin_right = 202.0
anchor_bottom = 1.0 margin_bottom = 18.0
margin_left = 4.0
margin_top = 32.0
margin_right = -4.0
margin_bottom = -4.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 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 bbcode_enabled = true
meta_underlined = false fit_content_height = true
script = ExtResource( 1 ) script = ExtResource( 19 )
[node name="search" type="VBoxContainer" parent="c/div1/div2/c/c/meta_tabs"] [node name="m" type="RichTextLabel" parent="c/div1/div2/c/c/c2/c"]
visible = false 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_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
margin_left = 4.0 margin_left = 4.0
@ -238,29 +377,18 @@ margin_right = -4.0
margin_bottom = -4.0 margin_bottom = -4.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
theme = SubResource( 10 )
[node name="le" type="LineEdit" parent="c/div1/div2/c/c/meta_tabs/search"]
margin_right = 58.0
margin_bottom = 24.0
size_flags_horizontal = 3
custom_fonts/font = ExtResource( 12 )
[node name="rte" type="RichTextLabel" parent="c/div1/div2/c/c/meta_tabs/search"]
margin_top = 28.0
margin_right = 58.0
margin_bottom = 28.0
size_flags_horizontal = 3
size_flags_vertical = 3
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 )
custom_fonts/normal_font = ExtResource( 12 ) custom_fonts/normal_font = ExtResource( 12 )
bbcode_enabled = true bbcode_enabled = true
meta_underlined = false meta_underlined = false
script = ExtResource( 15 ) text = "active: False
"
script = ExtResource( 1 )
[node name="meta" type="RichTextLabel" parent="c/div1/div2/c/c/meta_tabs"] [node name="meta" type="RichTextLabel" parent="c/div1/div2/c/c/c/meta_tabs"]
visible = false visible = false
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
@ -270,7 +398,7 @@ margin_right = -4.0
margin_bottom = -4.0 margin_bottom = -4.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
theme = SubResource( 3 ) theme = SubResource( 11 )
custom_constants/table_hseparation = 16 custom_constants/table_hseparation = 16
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 )
@ -279,7 +407,7 @@ custom_fonts/normal_font = ExtResource( 12 )
bbcode_enabled = true bbcode_enabled = true
script = ExtResource( 9 ) script = ExtResource( 9 )
[node name="sys" type="RichTextLabel" parent="c/div1/div2/c/c/meta_tabs"] [node name="search" type="VBoxContainer" parent="c/div1/div2/c/c/c/meta_tabs"]
visible = false visible = false
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
@ -289,7 +417,69 @@ margin_right = -4.0
margin_bottom = -4.0 margin_bottom = -4.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
theme = SubResource( 4 )
[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_constants/table_hseparation = 101
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 )
@ -300,10 +490,27 @@ meta_underlined = false
text = "idwords ⯆unique" text = "idwords ⯆unique"
script = ExtResource( 17 ) 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 = 566.0 margin_bottom = 562.0
rect_min_size = Vector2( 100, 0 ) rect_min_size = Vector2( 100, 0 )
size_flags_vertical = 3 size_flags_vertical = 3
@ -311,20 +518,38 @@ 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 = 559.0 margin_bottom = 555.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 = 270.0 margin_bottom = 448.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
[node name="list_symbols" type="RichTextLabel" parent="c/div1/div2/c2/c/c"] [node name="c" type="VBoxContainer" 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
theme = SubResource( 5 ) __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 )
@ -337,11 +562,12 @@ 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 = 282.0 margin_top = 460.0
margin_right = 166.0 margin_right = 166.0
margin_bottom = 552.0 margin_bottom = 548.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
@ -350,7 +576,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( 6 ) theme = SubResource( 15 )
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 )
@ -400,3 +626,7 @@ 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,12 +4,15 @@ class_name TE_ExtensionHelper
var symbols:Dictionary = {} var symbols:Dictionary = {}
func get_tab() -> String:
return " "
func generate_meta(t:TextEdit, r:RichTextLabel): func generate_meta(t:TextEdit, r:RichTextLabel):
var chars = TE_Util.commas(len(t.text)) var chars = TE_Util.commas(len(t.text))
var words = TE_Util.commas(len(t.text.split(" ", false))) var words = TE_Util.commas(len(t.text.split(" ", false)))
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]
@ -68,6 +71,23 @@ 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_TextEditor, t:TextEdit): func apply_colors(e:TE_Editor, 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,6 +27,7 @@ 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,33 +17,32 @@ 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_TextEditor, t:TextEdit): func apply_colors(e:TE_Editor, t:TextEdit):
.apply_colors(e, t) .apply_colors(e, t)
# vars # vars
t.add_color_region(' "', '"', e.color_var) t.add_color_region(' "', '"', e.color_varname)
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("//", "", e.color_comment, true) t.add_color_region('\t"#"', ",", e.color_comment, false)

View File

@ -1,14 +1,137 @@
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_TextEditor, t:TextEdit): func apply_colors(e:TE_Editor, t:TextEdit):
.apply_colors(e, t) .apply_colors(e, t)
t.add_keyword_color("true", e.color_var) var code:Color = lerp(Color.white.darkened(.5), Color.deepskyblue, .333)
t.add_keyword_color("false", e.color_var) var quote:Color = lerp(e.color_text, e.color_symbol, .5)
t.add_color_override("function_color", e.color_text)
t.add_color_override("number_color", e.color_text)
# 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)
@ -18,33 +141,40 @@ func apply_colors(e:TE_TextEditor, 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("> ", "", e.color_text.darkened(.6), true) t.add_color_region("> ", "", quote, true)
# comment # comment
t.add_color_region("<!--", "-->", e.color_comment, false) t.add_color_region("<!--", "-->", e.color_comment, false)
# headings # non official markdown:
var head = e.color_symbol # formatted
var tint1 = TE_Util.hue_shift(head, -.33) t.add_color_region("{", "}", lerp(e.color_text, e.color_var, .5).darkened(.25), false)
var tint2 = TE_Util.hue_shift(head, .33) # t.add_color_region("[", "]", lerp(e.color_text, e.color_var, .5).darkened(.25), false)
for i in range(1, 6): # t.add_color_region("(", ")", lerp(e.color_text, e.color_var, .5).darkened(.25), false)
var h = "#".repeat(i) if false:
t.add_color_region("%s *" % h, "*", tint1, true) # quote
t.add_color_region("%s \"" % h, "\"", tint2, true) t.add_color_region('"', '"', quote, false)
t.add_color_region("%s " % h, "*", head, true) # brackets
t.add_color_region('(', ')', quote, false)
else:
# url links # url links
# t.add_color_region("[]", ")", e.color_var.lightened(.5))
t.add_color_region("![", ")", e.color_var.lightened(.5)) t.add_color_region("![", ")", e.color_var.lightened(.5))
# headings
for i in range(1, 7):
var h = "#".repeat(i)
t.add_color_region("%s *" % h, "*", e.get_symbol_color(i-1, -.33), true)
t.add_color_region("%s \"" % h, "\"", e.get_symbol_color(i-1, .33), true)
t.add_color_region("%s " % h, "*", e.get_symbol_color(i-1), true)
# lists # lists
t.add_color_region("- [x", "]", Color.yellowgreen, false) t.add_color_region("- [x", "]", Color.yellowgreen, false)
t.add_color_region("- [", " ]", e.color_text.darkened(.6), false) t.add_color_region("- [", " ]", e.color_text.darkened(.6), false)
# code blocks # code blocks
var code:Color = lerp(e.color_text.darkened(.5), Color.yellowgreen, .5)
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)
@ -58,7 +188,6 @@ func apply_colors(e:TE_TextEditor, t:TextEdit):
# 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()
@ -66,11 +195,33 @@ 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
if lines[i].begins_with("#"): elif 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 = p[1].strip_edges() var name = "???" if len(p) == 1 else p[1].strip_edges()
last = add_symbol(i, deep, name) last = add_symbol(i, deep, name)
# tags # tags

View File

@ -0,0 +1,50 @@
tool
extends TE_ExtensionHelper
func get_tab() -> String:
return " "
func apply_colors(e:TE_Editor, t:TextEdit):
.apply_colors(e, t)
for k in "label menu define default scene show with play return jump call".split(" "):
t.add_keyword_color(k, e.color_symbol)
# strings
t.add_color_region('"', '"', e.color_var)
# bools
t.add_keyword_color("True", e.color_var)
t.add_keyword_color("False", e.color_var)
# comments
t.add_color_region("#", "", e.color_comment, true)
t.add_color_region("$ ", "", e.color_comment, true)
func get_symbols(t:String):
var out = .get_symbols(t)
var last = add_symbol()
var lines = t.split("\n")
var i = 0
while i < len(lines):
# symbols
if lines[i].begins_with("label "):
var key = lines[i].substr(len("label ")).strip_edges()
key = key.substr(0, len(key)-1)
last = add_symbol(i, 0, key)
elif lines[i].begins_with("menu "):
var key = lines[i].substr(len("menu ")).strip_edges()
key = key.substr(0, len(key)-1)
last = add_symbol(i, 0, key)
# tags
elif "#" in lines[i]:
var p = lines[i].rsplit("#", true, 1)[1]
if "#" in p:
for tag in p.split("#"):
last.tags.append(tag)
i += 1
return out

View File

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

View File

@ -1,6 +1,9 @@
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():
@ -43,7 +46,7 @@ func toggle_comment(t:TextEdit, head:String="", tail:String=""):
return [old, new] return [old, new]
func apply_colors(e:TE_TextEditor, t:TextEdit): func apply_colors(e:TE_Editor, t:TextEdit):
.apply_colors(e, t) .apply_colors(e, t)
# strings # strings

View File

@ -5,6 +5,8 @@
[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,6 +5,8 @@
[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,6 +5,8 @@
[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,6 +5,8 @@
[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,6 +5,8 @@
[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.

After

Width:  |  Height:  |  Size: 478 B

View File

@ -0,0 +1,35 @@
[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.

After

Width:  |  Height:  |  Size: 478 B

View File

@ -0,0 +1,35 @@
[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.

After

Width:  |  Height:  |  Size: 478 B

View File

@ -0,0 +1,35 @@
[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.

After

Width:  |  Height:  |  Size: 478 B

View File

@ -0,0 +1,35 @@
[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.4" version="1.12"
script="plugin.gd" script="plugin.gd"

View File

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

3
default_bus_layout.tres Normal file
View File

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