Skip to content

Commit

Permalink
fix: Handling of binary files (open-anyway, not caching editor) (nigh…
Browse files Browse the repository at this point in the history
…tly)
  • Loading branch information
tomlin7 committed Apr 11, 2024
1 parent 2674fc6 commit 28b627e
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 8 deletions.
2 changes: 2 additions & 0 deletions biscuit/core/components/editors/texteditor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def __init__(self, master, path=None, exists=True, language=None, minimalist=Fal
self.exists = exists
self.editable = True
self.run_command_value = None
self.unsupported = False

if not self.standalone:
self.__buttons__ = [('sync', self.base.editorsmanager.reopen_active_editor),]
Expand Down Expand Up @@ -119,6 +120,7 @@ def on_scroll(self, *_):
self.event_generate("<<Scroll>>")

def unsupported_file(self):
self.unsupported = True
self.text.show_unsupported_dialog()
self.linenumbers.grid_remove()
self.scrollbar.grid_remove()
Expand Down
29 changes: 23 additions & 6 deletions biscuit/core/components/editors/texteditor/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import tkinter as tk
import typing
from collections import deque
from tkinter.messagebox import askokcancel

import chardet
import tarts as lsp
Expand Down Expand Up @@ -40,6 +41,7 @@ def __init__(self, master: TextEditor, path: str=None, exists: bool=True, minima
self.minimalist = minimalist
self.standalone = standalone
self.language = language
self.unsupported = False

self.ctrl_down = False
self.buffer_size = 4096
Expand Down Expand Up @@ -802,6 +804,15 @@ def reopen(self, encoding=None, eol=None) -> None:
def load_file(self):
if not self.path or not self.exists:
return

if not textutils.is_text_file(self.path):
if not askokcancel("Binary File", "This file is a binary file, do you want to open it anyway?"):
# show unsupported file message and terminate content loading process
return self.master.unsupported_file()
else:
# just set the flag to True so that we don't cache editor content
self.master.unsupported = True
self.unsupported = True

self.clear()
try:
Expand All @@ -810,7 +821,7 @@ def load_file(self):
self.eol = textutils.get_default_newline()

self.queue = queue.Queue()
threading.Thread(target=self.read_file, args=(file,)).start()
threading.Thread(target=self.read_file, args=(file,), daemon=True).start()
self.process_queue()
except Exception as e:
print(e)
Expand Down Expand Up @@ -849,7 +860,7 @@ def write_with_buffer():
if not self.standalone:
self.base.statusbar.on_open_file(self)

threading.Thread(target=write_with_buffer).start()
threading.Thread(target=write_with_buffer, daemon=True).start()

def read_file(self, file):
while True:
Expand All @@ -873,14 +884,19 @@ def process_queue(self, eol: str=None):
try:
self.master.on_change()
self.master.on_scroll()
except ValueError:
except Exception:
pass
break
if eol:
chunk.replace(self.eol or textutils.get_default_newline(), eol)
self.write(chunk)
self.update()
self.master.on_scroll()

try:
self.write(chunk)
self.update()
self.master.on_scroll()
except Exception:
# editor was closed during file load
return
except queue.Empty:
# If the queue is empty, schedule the next check after a short delay
self.master.after(100, self.process_queue)
Expand Down Expand Up @@ -1085,6 +1101,7 @@ def set_active(self, flag=True):

def show_unsupported_dialog(self):
self.minimalist = True
self.unsupported = True
self.highlighter.lexer = None
self.set_wrap(True)
self.configure(font=('Arial', 10), padx=10, pady=10)
Expand Down
2 changes: 1 addition & 1 deletion biscuit/core/components/floating/palette/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Palette(Toplevel):
Palette is an action menu centered horizontally and aligned to top of root.
They contain a list of actions.
"""
def __init__(self, master: App, width=60, *args, **kwargs) -> None:
def __init__(self, master: App, width=80, *args, **kwargs) -> None:
super().__init__(master, *args, **kwargs)
self.config(pady=1, padx=1, bg=self.base.theme.border)

Expand Down
2 changes: 1 addition & 1 deletion biscuit/core/layout/base/content/editors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def close_editor(self, editor: Editor) -> None:
self.base.language_server_manager.tab_closed(editor.content.text)

# not keeping diff/games in cache
if not editor.diff and editor.content:
if editor.content and not (editor.diff or editor.content.unsupported):
self.closed_editors[editor.path] = editor
else:
editor.destroy()
Expand Down
19 changes: 19 additions & 0 deletions biscuit/core/utils/textutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,22 @@ def get_default_newline():

return os.linesep


# CREDITS: https://eli.thegreenplace.net/2011/10/19/perls-guess-if-file-is-text-or-binary-implemented-in-python/
int2byte = lambda x: bytes((x,))
_text_characters = (
b''.join(int2byte(i) for i in range(32, 127)) +
b'\n\r\t\f\b')

def is_text_file(path: str) -> bool:
fp = open(path, 'rb')
block = fp.read(512)
fp.close()

if b'\x00' in block:
return False
elif not block:
return True

nontext = block.translate(None, _text_characters)
return float(len(nontext)) / len(block) <= 0.30

0 comments on commit 28b627e

Please sign in to comment.