From 13908d7ba767b6415bf0880e491e0a33c3755fce Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Sun, 22 Mar 2026 00:35:11 -0500 Subject: [PATCH] Refactor file loading to detect external modifications and add reload capability - Extract _load_data() method from load_path() for reuse in reload() - Add is_extters externally_modified() to track file state changes (mtime/size) - Replace load_bytes() with load_contents() for better error handling - Add reload() method to re-read file from disk - Fix file_state_watcher by properly detecting external changes - Update TODO list (add Terminal plugin, mark file_state_watcher as fixed) --- TODO.md | 2 +- .../prettify_json/prettify_json.py | 4 +- src/core/widgets/code/source_file.py | 62 ++++++++++++------ src/newton.zip | Bin 118388 -> 118601 bytes 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/TODO.md b/TODO.md index 3056e78..b29c642 100644 --- a/TODO.md +++ b/TODO.md @@ -3,6 +3,7 @@ ___ 1. Add Godot LSP Client 1. Add TreeSitter 1. Add Collapsable code blocks +1. Add Terminal plugin 1. Add Plugin to | and | to split views up, down, left, right 1. Add i to **lsp_manager** to list who implements xyz @@ -13,7 +14,6 @@ ___ ___ ### Fix -- Fix **file_state_watcher** to prompt refrsh if external changes applied - Fix on lsp client unload to close files lsp side and unload server endpoint - Fix multi-select left/right block select movement de-sync from leader when '_' in word diff --git a/plugins/code/event-watchers/prettify_json/prettify_json.py b/plugins/code/event-watchers/prettify_json/prettify_json.py index ad03e62..ae32086 100644 --- a/plugins/code/event-watchers/prettify_json/prettify_json.py +++ b/plugins/code/event-watchers/prettify_json/prettify_json.py @@ -13,8 +13,6 @@ from gi.repository import Gtk def add_prettify_json(buffer, menu): - menu.append(separator) - def on_prettify_json(menuitem, buffer): start_itr, \ end_itr = buffer.get_start_iter(), buffer.get_end_iter() @@ -28,4 +26,4 @@ def add_prettify_json(buffer, menu): item = Gtk.MenuItem(label = "Prettify JSON") item.connect("activate", on_prettify_json, buffer) - menu.append(item) + menu.append(item) \ No newline at end of file diff --git a/src/core/widgets/code/source_file.py b/src/core/widgets/code/source_file.py index c21b8cf..1e3efc2 100644 --- a/src/core/widgets/code/source_file.py +++ b/src/core/widgets/code/source_file.py @@ -120,21 +120,7 @@ class SourceFile(GtkSource.File): return gfile - - def load_path(self, gfile: Gio.File): - if not gfile: return - - text = gfile.load_bytes()[0].get_data().decode("UTF-8") - info = gfile.query_info('standard::content-type', Gio.FileQueryInfoFlags.NONE, None) - content_type = info.get_content_type() - self.ftype = Gio.content_type_get_mime_type(content_type) \ - .replace("application/", "") \ - .replace("text/", "") \ - .replace("x-", "") - - self.set_path(gfile) - logger.debug(f"File content type: {self.ftype}") - + def _load_data(self, text: str, is_new: bool = True): undo_manager = self.buffer.get_undo_manager() self.buffer.block_changed_signal() @@ -151,21 +137,49 @@ class SourceFile(GtkSource.File): self.buffer.delete(start_itr, end_itr) self.buffer.insert(start_itr, text, -1) + self.is_externally_modified() GLib.idle_add(move_insert_to_start) undo_manager.end_not_undoable_action() self.buffer.set_modified(False) - eve = Event_Factory.create_event( - "loaded_new_file", - file = self - ) - self.emit(eve) + if is_new: + eve = Event_Factory.create_event( + "loaded_new_file", + file = self + ) + self.emit(eve) self.buffer.unblock_changed_signal() self.buffer.unblock_changed_after_signal() self.buffer.unblock_modified_changed_signal() + def is_externally_modified(self) -> bool: + stat = os.stat(self.fpath) + current = (stat.st_mtime_ns, stat.st_size) + + is_modified = \ + hasattr(self, "last_state") and not current == self.last_state + + self.last_state = current + return is_modified + + def load_path(self, gfile: Gio.File): + if not gfile: return + loaded, contents, etag_out = gfile.load_contents() + if not loaded: raise Exception("File couldn't be loaded...'") + + text = contents.decode("UTF-8") + info = gfile.query_info('standard::content-type', Gio.FileQueryInfoFlags.NONE, None) + content_type = info.get_content_type() + self.ftype = Gio.content_type_get_mime_type(content_type) \ + .replace("application/", "") \ + .replace("text/", "") \ + .replace("x-", "") + + self.set_path(gfile) + logger.debug(f"File content type: {self.ftype}") + self._load_data(text) def set_path(self, gfile: Gio.File): if not gfile: return @@ -177,9 +191,17 @@ class SourceFile(GtkSource.File): event = Event_Factory.create_event("file_path_set", file = self) self.emit(event) + def reload(self): + loaded, contents, etag_out = self.get_location().load_contents() + if not loaded: raise Exception("File couldn't be re-loaded...'") + + text = contents.decode("UTF-8") + self._load_data(text, False) + def save(self): self._write_file( self.get_location() ) + self.is_externally_modified() self.buffer.set_modified(False) event = Event_Factory.create_event( "saved_file", diff --git a/src/newton.zip b/src/newton.zip index 91ddfa80467ac245a87d9aa4d907579460f9b7df..ff688c4f7d3b671ca934d6736e11fe494d938a81 100644 GIT binary patch delta 4519 zcmY*d2{@Ho7e4!wj-d=886#zi5E;@yMTI)bm?05OBtxM~j+qqENjsT~GDgNsAyY_X zXrkyQC8U8{src9Nx&2+w<8jveu5qum*FKNQL~2ViwSYyR7_MTl>dP&3^QbxM?!kB@ zBEmadb;{<|>Q9gD7E&mJLKKPwBaJ42cLgFU{t$rJ+1V*9Ol>z0Mzp>t{durct+`ck z_&pttV!cwf&Krsq)dD<6oYPmWILEbf{E*2|jrXBU>Qup#-NLCAmXH1F?G3uM%cvH|8#igMJi>h+s0w>XVvx-Q(xw5RS#L}PPS7MVy z{LFGLq6VEgm#XJFsjEDhnMe0{zF}R{0*8*BkMh2>zUx%i4$|)(j^!5eQePt18=&@Q%MUPv^-;%s%)KZsepE#A@|+5 zj8Mt0oD;RXIQWwivJh|Lr zh84?IWK7~%U+<+(9B%XHAjo1&dXVz(~4wqxVVztl#2GNQ=W)E ze3ts)Vl^6(aC#Lp6ye~!Yg@g9rvlqIo3)5Ve|aA2AsnA`P|+ZhBYU-(*3!-OQ?m^vv;@70pIJvYXvfm?3glWP zZ$z=HjF0l@JQm^X-uubEu(KvQCnQ(6+ zF0n9nyZ2(Xl+T_mhh3BxZJtuudTp(J>b4Whbu^=dB{FZW-p4^RU2E=}bk0C~kM)@J zeSJxfefVMImdnp0a@C)HZA6>1TG;5t>C$-D6nGRp|oXy?E$h zrpyQ4EJv*ld___(|nI@71+O{ad=cn%t)I*sP43UN`;UpueMF>@UT+E z0eY>1mUhQz;#*VGBu<;;`XwihISz`HHm$Z&+sJDsc}RwRWQ}{0y}`uS)LZ7p)e9yLUp9It4_dxiIZ?l#<2c_m-`DMJF9j5oUkmPR z)d;Vh9PB|k_ipL^Xw2pgK3kmR-t)s(XQaBgi>}pO+|1T7WHZ6F!scxDd5gk_hfHW2 zkEpR$Q^wV-UUP|QcB?iXziLrOv$C;H>nJLDI@+3c)Nw(g!d_cGJO6Sg!@Lbw{yt>0 zncz~0WBv60mw2?zCf@SE*N>g_E1!y~?dYFUxE}D{RdxJu;kpo8r+n3jgoLnKm$*^N z#2G&edhlt3o%~9%?eYxiKG%fX>L+~*Y`pt_>JC1Ms8)2cXK2(^pDr2JQ@byeAAeC= zI4!VTC~Tnl*+a}f#wWxPE0-lM`^Hj<^~b zd>Y&n{oJdj(I!8rUyj3dwz4APi`QK(^;b$RGb8k~-C`! zbsswVx3b3foLIA6v!Y-4l~)&WhD)%SQ+9Q9PHe z#qyW;spAJcZxk!Zj=cS>yQy|8%F3tV3a7h=u~t!-oeI64Mc_1USM2(-J*)P@=tC1n znK(vH{wnUy^?#B{!~=Iu{YPY zzP|BpkJs9`J7+`-y3*no(w2vpCG{uEOa{)TRJ?VNPjn4SGg7Ni7}05$x$4}!acV{> zSk9{11|SW>%>xH|A~CN2zEij^0BOy0l2|Md2@^9$I4uzIGoP-#gaeH! zI1}}Af90@75ZXmp8#6&UoF9bjQ7m=~Mxt0T7;QmA%+E&&do%1Fj70E1!N`iJw;+Y% zA;^MAvY8VYv(`d*It1wunfu9L#-ZR>(C&9+Dy|4cI|*|KCbATZgdrp1og+z~2}3j# zgH^(jB>oTvVc#)7dlB!B&nYuv+&LJuhUkI1Xo2s z9$FOysgDqu=Vl$SCt3HpG79bO`qQYgBHq)g(4w!f8XCAj*dh=nY09sTm zbPjDHj064z`52vaL7aCE!ViZ0Nl>xqdGPsn=%3&!JQfZ0^q+^EV#EJr_^?V8GABAB zeuFqa3ONv;&iw`;1wL#PjZBI3sQ-d}(P$6xH2VLbUi1=tJ`6e<(~3B8)CDAjG_hn1 z5}Z5Nl-Ol>@B(Dq!N4dMNnyPhs7wA5*1e4683~L}V_|8DP3H_8g zfl;2!i>a4DKlc*occhXklb4`V2dN?qBhGjYz*D?z82f=T8 z;PMQnf)~+wgLL!eGMvuhOs1fSoiOBZAd6%MFdSxo_ME_=WebowBwm3W%5q6mK34#L zzXC<`-@<#Yp|$vUJlrU^d}f`eiP-|u(UGfAOmHD-^3QG2%L!m{x0obd6QB(3GE$gG zfXSV>LkixBaAu7aOhJ*MRl$$hlfaIxYK~?2Rtn(rOdzJ31Zdf;cs2=clvvH23HDA# z#)M5R$#&E%#T~8C^HhJtfmKqVh?2TF3ZG5^J@$H1&+i^T=1c{*Lk%P#pUa6uQejqg zn@IK9RJ4!y+)N5#X~6ijkOFj&mGSXDJLbLy4l-MrM-ogB4@gI++IX<{W$2>jbtKGU z)=pt0J&?ja*O3m@vy(z`IqHA|{9(dIJO10S!cNSZjw}h4Zfuv1%m|lWT$+xISqgh8 zjOiX(=8~DO$|3^^qxaY&139ud^-&mk&xOeiA#?*G_5vc-CxR8*AqQ_J^5!Llq4-jY z=|LL50EAjNNG7u9FSHJ;-h@Nqe}!o`q2SyhoP874Tj*PivJoG1D~aQnbU4dRnV{A= z4;n@x%%b&?!U&uY z!C~0|mVd(cvtgFdXDph7Y+0f{Qy8hAm*O}-h+B|@RKvT8QTN;?ON9 zY7rX=J5$jj%$^8`WRMTAG&>3V=OaU+m6H_YIKlK|K16q2Od{=zzzVJ{teJG!?-2!v zi`dGIuM|MKVcZBmk8bT#p_{2&`Y`hqh z?^l5G4r!A6Q32yDB|{3%mGGcx$dUpaofV-gM+zyjNQgYbeRAL|wF)gFB;@C~xl~%J zU`tK@0hr4pG4dRIsv+F#)ntcqtD$uR3Z&DG3ZP?G2PqxB3p%5U|N3LayA`2jbEUmt zQXOkZ^EGQ=Fy`8^y9VG|CDIWTxE!a}zlA0OB;_j!dPr>L6GUp82_HTR#9Ow_< z&Ym@agZta?R1@0660eW&D?K-)G{+fv3GOB_FhN><0iz#Hf@P0ZZ4+|C9TK`J;jgOV0LBO;OffQVcs@qS8y9#kB9Su@dNlb$;URdok+DO zX+VsLn1jCsDz1G1&)04z%-If`>fjN4q8-_yDcs%;hfwN*l^&wa3mZL|@A&@!1v)mL delta 4200 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 YzCVa^a5BGMJ%wK%J2tkN0Osxd4>&xZF8}}l