------------------------------------------------------------------------------- --# BEAR (Browse, Edit And Run) ------------------------------------------------------------------------------- -- Requires EuGTK version 4.11.10, GtkSourceView and WebKit2Gtk libraries. -- You may have to manually change the names of the libraries in GtkSourcView.plugin -- and/or GtkWebKit.plugin! include GtkEngine.e include GtkFileSelector.e include GtkFontSelector.e include GtkSettings.e include GtkWebKit.plugin include GtkSourceView.plugin include GtkAboutDialog.e include std/net/url.e include std/net/http.e ------------------------------ -- Globals ------------------------------ object current_web_page = "documentation/README.html" object current_net_page = "" object current_edit_file = "" object current_font = "Ubuntu mono 12" object current_web_folder = "~/demos" object current_edit_folder = "~/demos" object current_style = "classic" object uri, link, lang, tags = {} object svbuffer, request, lm, edit_html = 0 constant cb = create(GtkClipboard) constant ini = canonical_path("~/.bear.ini") atom sv, menu, m1, m2, m3, m4, m5, sep, context atom wvsettings, svsettings, controller,sig integer toggle = 1, show_map = 0 -- map not used ----------------------------- -- Styling ----------------------------- constant css = create(GtkCssProvider,` @define-color yellow #F5EEB5; @define-color blue #B5F5F4; GtkFrame,GtkToolbar {border-radius: 10px; background-image: -gtk-gradient (linear, left top, right bottom, from(@yellow), to(@blue)); } `) constant mgr = create(GtkSourceStyleSchemeManager) constant ids = get(mgr,"scheme ids") sequence sty = repeat(0,length(ids)) sty[1] = create(GtkRadioMenuItem,0,ids[1],_("SelectStyle"),ids[1]) for i = 2 to length(ids) do sty[i] = create(GtkRadioMenuItem,sty[i-1], ids[i],_("SelectStyle"),ids[i]) end for ---------------------------- -- Interface ---------------------------- constant win = create(GtkWindow,"name=MainWindow,title=The Bear,size=1200x800,border=10,$delete-event=Bail") add("MainWindow",create(GtkBox,"name=top,orientation=VERTICAL")) pack("top",create(GtkButtonBox,"name=bar,layout=2,margin-bottom=5")) add("bar",{ -- these display current file names, captions, and language type; create(GtkFrame,"name=frame1"), create(GtkFrame,"name=frame2"), create(GtkFrame,"name=frame3"), create(GtkFrame,"name=frame4")}) add("frame1",create(GtkLabel,"name=label1,text=URL,font=8")) add("frame2",create(GtkLabel,"name=label2,text=TITLE,font=8")) add("frame3",create(GtkLabel,"name=label3,text=LANG,font=8")) add("frame4",create(GtkLabel,"name=label4,text=FILE,font=8")) pack("top",create(GtkPaned,"name=paned,orientation=HORIZONTAL,position=600"),TRUE,TRUE) set("paned","pack1",create_webview(),1,1) -- left side contains web view; set("paned","pack2",create(GtkBox,"name=pane2,orientation=VERTICAL"),TRUE,TRUE) pack("pane2",create_sourceview(),1,1) -- right side contains source view; pack_end("top",create(GtkBox,"name=control_box,orientation=HORIZONTAL,spacing=5")) pack("control_box",{ -- container for controls at bottom of screen; create(GtkFrame,"name=frame5,label=Web Page"), create(GtkFrame,"name=frame6,label=Source")},TRUE,TRUE) add("frame5",create(GtkToolbar,"name=bar1,style=2,icon size=1,font=8")) add("bar1",{ -- buttons for web page navigation; create(GtkToolButton,"name=netOpen,icon_name=www,label=Network",,_("OpenNetPage")), create(GtkToolButton,"name=htmlOpen,stock-id=gtk-open,label=Local",,_("OpenWebPage")), create(GtkToolButton,"name=htmlEdit,stock-id=gtk-edit",,_("EditHtml")), create(GtkToolButton,"name=htmlBack,stock-id=gtk-go-back",,_("Back")), create(GtkToolButton,"name=htmlFwd,stock-id=gtk-go-forward",,_("Fwd")), create(GtkToolButton,"name=htmlFind,stock-id=gtk-find",,_("Find")), create(GtkToolButton,"name=zoomOut,stock-id=gtk-zoom-out",,_("ZoomOut")), create(GtkToolButton,"name=zoomIn,stock-id=gtk-zoom-in",,_("ZoomIn")), create(GtkToolButton,"name=htmlHelp,stock-id=gtk-help",,_("Help"))}) add("frame6",create(GtkToolbar,"name=bar2,style=2,icon size=1,font=8")) add("bar2",{ -- buttons for source view navigation; create(GtkToolButton,"name=srcNew,stock-id=gtk-new",,_("fileNew")), create(GtkToolButton,"name=srcOpen,stock-id=gtk-open",,_("fileOpen")), create(GtkToolButton,"name=srcSave,stock-id=gtk-save",,_("fileSave")), create(GtkToolButton,"name=srcSaveAs,stock-id=gtk-save-as",,_("fileSaveAs")), create(GtkToolButton,"name=srcRun,stock-id=gtk-execute",,_("fileRun")), create(GtkSeparatorToolItem,"draw=TRUE,expand=TRUE"), create(GtkMenuToolButton,"name=srcMenu,stock-id=gtk-preferences"), create(GtkToolButton,"name=srcAbout,stock-id=gtk-about",,_("About"))}) connect("srcMenu","clicked",_("Preferences")) set("srcMenu","menu",build_prefs_menu()) connect("srcMenu","clicked",_("PopupSrcMenu")) connect("MainWindow","realize",_("on_startup")) show_all("MainWindow") --set("MainWindow","interactive debugging",1) main() ------------------ function fileNew() ------------------ fileselector:do_overwrite_confirmation = TRUE fileselector:filters = {"euphoria","html","text"} object f = fileselector:New() if not atom(f) then create_file(f) end if return 1 end function -------------------- function fileOpen() -------------------- fileselector:filters = {"euphoria","html","css","text"} object f = fileselector:Open(current_edit_folder & "/*") if not atom(f) then load_file(f) current_edit_folder = pathname(f) end if return 1 end function -------------------- function fileSave() -------------------- object f atom fn fileselector:do_overwrite_confirmation = FALSE if match("http://",current_edit_file) = 1 then f = fileselector:Save(canonical_path(filename(fix(decode(current_edit_file))))) else f = canonical_path(get("label4","text")) fileselector:filters = {fileext(f)} & {"text"} chdir(pathname(f)) f = fileselector:Save(f) end if if string(f) then fn = open(f,"w") write_file(fn,get(svbuffer,"text"),TEXT_MODE) flush(fn) close(fn) if match("htm",fileext(f)) = 1 then set("WebView","reload bypass cache") current_web_folder = pathname(f) else current_edit_folder = pathname(f) end if end if return 1 end function ----------------------- function fileSaveAs() ----------------------- fileselector:do_overwrite_confirmation = TRUE object f = filename(current_edit_file) fileselector:filters = {fileext(f)} & {"text"} f = fileselector:SaveAs(f & ".backup") if string(f) then write_file(f,get(svbuffer,"text"),TEXT_MODE) if match("htm",fileext(f)) = 1 then current_web_folder = pathname(f) else current_edit_folder = pathname(f) end if end if return 1 end function ------------------ function fileRun() ------------------ object f = current_edit_file object cmd = command_line() atom fn cmd = pathname(get("label4","text")) f = filebase(f) object tmp = temp_file(canonical_path("~/"),sprintf("tmp/%s_",{f}),"ex",1) if not file_exists(canonical_path("~/tmp")) then create_directory(canonical_path("~/tmp"),448,1) end if fn = open(tmp,"w") write_file(fn,get(svbuffer,"text"),TEXT_MODE) flush(fn) close(fn) setenv("EUINC",canonical_path("~/demos")) system(text:format("eui [] & ",{tmp}),0) return 1 end function ------------------------------- function create_file(object f) ------------------------------- object hdr lang = get(lm,"guess language",f) set(svbuffer,"language",lang) name = get(lang,"name") switch name do case "Euphoria" then hdr = euhdr case "Python" then hdr = pyhdr case ".ini" then hdr = inihdr case "C","CSS","C++","C/C++/ObjC Header" then hdr = chdr case else hdr = "-- []\n\n" end switch set(svbuffer,"text",format(hdr,{f})) set("label3","text",get(lang,"name")) set("label4","text",f) write_file(f,get(svbuffer,"text")) current_edit_file = f current_edit_folder = pathname(f) return update_buttons() end function ------------------------------------------- function load_file(object f, integer web=0) ------------------------------------------- object txt if match("file://",lower(f)) then f = f[8..$] end if if file_exists(canonical_path(f)) then txt = read_file(canonical_path(f)) else if not networked() then return Warn(,,"Network down") end if if not match("http://",f) = 1 then f = "http://" & f end if txt = http_get(f) if atom(txt) then Error(,,"Error %d loading %s ",{txt,f}) return -1 else txt = txt[2] end if end if lang = get(lm,"guess language",f) set(svbuffer,"language",lang) set(svbuffer,"text",txt) set("label3","text",get(lang,"name")) set("label4","text",f) current_edit_file = f current_edit_folder = pathname(f) return update_buttons() end function ---------------------- function fix(object x) ---------------------- if match("#",x) then x = split(x,'#') x = x[1] end if if match("file:",x) = 1 then return x[8..$] end if if match("http:",x) = 1 then return x[8..$] end if if match("https:",x) = 1 then return x[9..$] end if return x end function ----------------------- function Back(atom ctl) ----------------------- set("WebView","go back") return update_buttons() end function ---------------------- function Fwd(atom ctl) ---------------------- set("WebView","go forward") return update_buttons() end function --------------- function Undo() --------------- set(svbuffer,"undo") return update_buttons() end function --------------- function Redo() --------------- set(svbuffer,"redo") return update_buttons() end function ------------------ function ZoomIn() ------------------ set("WebView","zoom level",get("WebView","zoom level") + .1) return 1 end function ------------------ function ZoomOut() ------------------ set("WebView","zoom level",get("WebView","zoom level") - .1) return 1 end function ------------------------- function update_buttons() ------------------------- integer x = get(svbuffer,"char count") set("netOpen","sensitive",networked()) set("srcSave","sensitive",x) set("srcSaveAs","sensitive",x) set("srcRun","sensitive",x) if string(current_edit_file) and equal("ex",fileext(current_edit_file)) then set("srcRun","sensitive",equal("ex",fileext(current_edit_file))) else set("srcRun","sensitive",FALSE) end if object uri = get("WebView","uri") if sequence(uri) and match("htm",uri) then set("htmlEdit","tooltip text",uri) set("label1","text",uri) set("label2","text",get("WebView","title")) end if return 1 end function ----------------------- function OpenNetPage() ----------------------- atom dlg = create(GtkDialog) set(dlg,"add button","gtk-cancel",MB_CANCEL) set(dlg,"add button","gtk-ok",MB_OK) atom ca = get(dlg,"content area") atom lbl = create(GtkLabel," Enter a web address beginning with http:// ") atom input = create(GtkEntry) add(ca,{lbl,input}) show_all(dlg) if match("file://",current_net_page) = 1 then set(input,"text","") elsif match("http://",current_net_page) = 1 then set(input,"text",current_net_page) else set(input,"text","http://" & current_net_page) end if object uri, request if run(dlg) = MB_OK then uri = get(input,"text") if length(uri) > 0 then request = create(WebkitUriRequest,decode(uri)) set("WebView","load request",request) end if end if destroy(dlg) return 0 end function ----------------------- function OpenWebPage() ----------------------- fileselector:filters = {"html","css"} object f = fileselector:Open(current_web_folder & "/*") if not atom(f) then load_html(f) current_web_folder = pathname(f) end if return 1 end function ---------------------------- function load_html(object x) ---------------------------- x = canonical_path(x) if file_type(x) = 1 then set(svsettings,"search text",0) request = create(WebkitUriRequest,"file://" & x) set("WebView","load request",request) set("label1","text",x) end if return 1 end function -------------------------------------------------- function on_load_changed(atom view, integer event) -------------------------------------------------- object uri, ext = "?", x = 0 object editables = {"e","ex","txt","text","ini","css","xml","glade","c","cpp","h"} set(svsettings,"search text","") switch event do case WEBKIT_LOAD_STARTED then uri = decode(get("WebView","uri")) ext = fileext(filename(uri)) if find(ext,editables) then set("WebView","stop loading") load_file(uri,0) end if case WEBKIT_LOAD_REDIRECTED then case WEBKIT_LOAD_COMMITTED then case WEBKIT_LOAD_FINISHED then uri = decode(get("WebView","uri")) if find(ext,editables) = 0 then current_web_page = uri end if current_net_page = uri end switch edit_html = 0 return update_buttons() end function -------------------------- function EditHtml() -------------------------- object f = canonical_path(fix(get("label1","text"))) edit_html = 1 if file_exists(f) then object txt = read_file(f) if not atom(txt) then load_file(f,1) end if else f = get("WebView","uri") if match("#",f) then f = split(f,'#') f = f[1] end if object content = http_get(f) if atom(content) then Error(,,"Cannot load web page",f) else lang = get(lm,"guess language",f) set(svbuffer,"language",lang) set("label3","text",get(lang,"name")) set("label4","text",f) set(svbuffer,"text",content[2]) current_edit_file = f update_buttons() end if end if return 1 end function -------------------------- function create_webview() -------------------------- atom webview = create(WebkitWebView,"name=WebView") atom vset = get(webview,"settings") set(vset,{ {"enable tabs to links",TRUE}, {"zoom text only",FALSE}, {"enable developer extras",TRUE}, {"enable smooth scrolling",TRUE}, {"enable_caret_browsing",TRUE}, {"draw_compositing_indicators",TRUE}, $}) connect(webview,"load-changed",_("on_load_changed")) wvsettings = get(webview,"settings") set(wvsettings,"enable plugins",1) set(wvsettings,"zoom text only",1) set(wvsettings,"enable smooth scrolling",1) --set(wvsettings,"auto load images",0) --set(wvsettings,"enable write console messages to stdout",1) --set(wvsettings,"enable spatial navigation",1) --set(wvsettings,"enable tabs to links",1) --set(wvsettings,"enable xss auditor",1) --set(wvsettings,"minimum font size",12) --set(wvsettings,"draw compositing indicators",1) set(wvsettings,"enable html5 database",1) set(wvsettings,"enable html5 local storage",1) set(wvsettings,"enable hyperlink auditing",1) controller = get(webview,"find controller") -- following are not implemented by webview yet; --context = get(webview,"context") --set(context,"preferred languages",{"en_US"}) --set(context,"spell checking languages",{"en_US"}) --set(context,"spell checking enabled",TRUE) return webview end function --------------- function Find() --------------- atom buffer = get(context,"buffer") object a = allocate(100) object b = allocate(100) object c = allocate(100) object x, count integer try = 1 atom fn = define_c_func(LIBSV,"gtk_source_search_context_forward",{P,P,P,P},I) object txt = get(cb,"wait for text") label "retry" c_proc(fnBufStart,{buffer,a}) c_proc(fnBufEnd,{buffer,b}) if string(txt) then txt = transmute(txt, {{},"<",">","&"}, {{},"<",">","&"}) txt = join(split(txt),"\\s+") set(svsettings,"regex enabled",1) set(svsettings,"search text",txt) count = get(context,"occurrences count") if count = -1 then try += 1 if try > 20 then return 0 end if goto "retry" else -- if count > 1 then -- if show_map then -- set("map","deiconify") -- set("map","present") -- end if -- else -- if show_map then -- set("map","iconify") -- end if -- end if x = c_func(fn,{context,a,b,c}) set(sv,"scroll to iter",b,.25,1,0,0) end if end if return 1 end function ----------------------------- function create_sourceview() ----------------------------- atom scroller = create(GtkScrolledWindow) sv = create(GtkSourceView,{ {"name","SrcView"}, {"show line numbers",TRUE}, {"tab width",4}, {"indent width",4}, {"indent on tab",TRUE}, {"auto indent",TRUE}, {"font","Ubuntu mono bold 12"}, {"show right margin",TRUE}, {"show line marks",TRUE}, {"draw spaces",FALSE}, {"insert spaces instead of tabs",FALSE}, {"right margin position",90}, {"highlight current line",TRUE}, {"wrap mode",GTK_WRAP_NONE}}) add(scroller,sv) set(sv,"font",current_font) -- map is commented out since only the latest WebView supports maps; -- atom win2 = create(GtkWindow,"name=map,border=10,size=80x800") -- atom smap = create(GtkSourceMap,"font=Ubuntu mono 4") -- -- set(smap,"view",sv) -- add(win2,smap) -- set(win2,"deletable",0) -- set(win2,"move",0,0) -- set(win2,"decorated",0) -- show_all(win2) -- set(win2,"visible",show_map) -- svbuffer = get(sv,"buffer") lm = create(GtkSourceLanguageManager) svsettings = create(GtkSourceSearchSettings) context = create(GtkSourceSearchContext,svbuffer,svsettings) set(svsettings,"at word boundaries",0) set(svsettings,"case sensitive",1) atom tt = get(svbuffer,"tag table") set(tt,"foreach",_("get_tags")) set(tags[1],"background","red") set(tags[1],"foreground","white") set(tags[1],"font","bold") return scroller end function function get_tags(atom tt) register(tt,GtkTextTag) tags = append(tags,tt) return 1 end function ------------------------------------ function ToggleMap() ------------------------------------ -- show_map = not(show_map) -- if show_map then set("map","deiconify") -- else set("map","iconify") -- end if return 1 end function ------------------------------------ function ToggleLineNumbers(atom ctl) ------------------------------------ set("SrcView","show line numbers",get(ctl,"active")) return 1 end function ------------------------------------ function ToggleSpaces(atom ctl) ------------------------------------ if get(ctl,"active") then set("SrcView","draw spaces",GTK_SOURCE_DRAW_SPACES_ALL) else set("SrcView","draw spaces",FALSE) end if return 1 end function ------------------------------------ function ChooseFont(atom ctl) ------------------------------------ fontselector:mono_filter = TRUE object x = fontselector:Select(current_font) if not atom(x) then set("SrcView","font",x) current_font = x end if return 1 end function ----------------------------- function build_prefs_menu() ----------------------------- menu = create(GtkMenu) m1 = create(GtkMenuItem,"Editor font",_("ChooseFont")) m2 = create(GtkCheckMenuItem,"Line numbers",_("ToggleLineNumbers")) m3 = create(GtkCheckMenuItem,"Draw spaces+tabs",_("ToggleSpaces")) m4 = create(GtkCheckMenuItem,"Show Map",_("ToggleMap")) atom sep1 = create(GtkSeparatorMenuItem) atom sep2 = create(GtkSeparatorMenuItem) set(menu,"append",{m1,sep1,m2,m3,sep2,sty}) set(m2,"name","ShowLineNumbers") set(m2,"active",get("SrcView","show line numbers")) set(m3,"name","DrawSpaces") set(m3,"active",get("SrcView","draw spaces")) set(m4,"name","ShowMap") set(m4,"active",show_map) set(menu,"name","popup_menu") show_all(menu) return menu end function -------------------------------------------- function SelectStyle(atom ctl, object name) -------------------------------------------- if atom(name) then name = unpack(name) end if atom scheme = get(mgr,"scheme",name) set(svbuffer,"style scheme",scheme) set(mgr,"force rescan") current_style = name return 1 end function ----------------------------- function Help() ----------------------------- object uri = "file://" & canonical_path("~/demos/documentation/bear.html") set("WebView","load uri",uri) return 1 end function ----------------------------- function About() ----------------------------- atom dlg = about:Dialog set(dlg,"program name","The Bear") set(dlg,"version","Version 1.3") set(dlg,"logo","thumbnails/mongoose.png") set(dlg,"add credit section","Using:", {"Euphoria " & version_string_short(),filename(svdll),filename(wkdll)}) run(dlg) hide(dlg) return 1 end function ----------------------------- function PopupSrcMenu() ------------------------------- set("popup_menu","popup") return 1 end function ------------------------------- function on_startup() ------------------------------- settings:Load(ini) object x = get("MainWindow","data","edit_file") if sequence(x) and length(x) > 0 and file_exists(canonical_path(x)) then load_file(canonical_path(x),1) end if x = get("MainWindow","data","current_web_folder") if sequence(x) and length(x) > 0 then current_web_folder = x end if x = get("MainWindow","data","current_net_page") if sequence(x) and length(x) > 0 then current_net_page = fix(x) load_html(current_net_page) end if x = get("MainWindow","data","current_edit-folder") if sequence(x) and length(x) > 0 then current_edit_folder = x end if x = get("MainWindow","data","current_style") if sequence(x) and length(x) > 0 then current_style = x x = find(current_style,ids) if x > 0 and x <= length(sty) then set(sty[x],"active",1) end if end if set("netOpen","tooltip text","Open a web page on the WWW") set("htmlOpen","tooltip text","Open a local html file") set("srcOpen","tooltip text","Open a local text file") return 1 end function ------------------------------- global function Bail() ------------------------------- settings:Save(ini,{"MainWindow","paned","ShowLineNumbers","DrawSpaces","FontSelector"}) settings:Add(ini,"MainWindow","data.edit_file",fix(current_edit_file)) settings:Add(ini,"MainWindow","data.current_web_folder",current_web_folder) settings:Add(ini,"MainWindow","data.current_net_page",fix(get("label1","text"))) settings:Add(ini,"MainWindow","data.current_edit_folder",current_edit_folder) settings:Add(ini,"MainWindow","data.current_style",current_style) settings:Add(ini,"SrcView","font",get("FontSelector","font")) -- line above sets the sv font on loading, but there's no direct way to -- save the sv font on exit, so we save the FontSelector current font instead, -- and use that value to restore the sv font. return Quit() end function -- Boilerplate for new files; constant euhdr = ` ---------------------------- -- [] ---------------------------- ` constant inihdr = ` ;--------------------------- ; [] ;--------------------------- ` constant pyhdr = ` #----------------------------- # [] #----------------------------- ` constant chdr = ` /* [] */ ` --========================================================================--