From 859787cdbb3851017283e5f0a58efa8dea4072de Mon Sep 17 00:00:00 2001 From: "R. Tyler Croy" Date: Sat, 14 Jan 2017 18:28:35 -0800 Subject: [PATCH] Add support for autocompletion of executables in PATH --- Makefile | 10 ++++++--- arun.glade | 2 -- src/arun-handlers.adb | 1 - src/arun-launchers-unix.adb | 40 ++++++++++++++++++++++++++++++++- src/arun-launchers-unix.ads | 5 +++++ src/arun-view.adb | 1 + src/arun.adb | 44 ++++++++++++++++++++++++++++++++++++- src/arun.ads | 15 +++++++++++++ 8 files changed, 110 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 062f1fa..098104f 100644 --- a/Makefile +++ b/Makefile @@ -2,11 +2,12 @@ GPRBUILD:=$(shell which gprbuild) GPRCLEAN:=$(shell which gprclean) EXE=obj/arun +GPRFILE=arun.gpr all: $(EXE) $(EXE): prepare - $(GPRBUILD) -Parun.gpr -cargs:c $(shell pkg-config --cflags gio-2.0) + $(GPRBUILD) -P$(GPRFILE) -cargs:c $(shell pkg-config --cflags gio-2.0) prepare: src/arun-resources.c mkdir -p obj @@ -17,8 +18,11 @@ src/arun-resources.c: arun.gresource.xml arun.glade run: all ./$(EXE) +doc: + gnatdoc -P$(GPRFILE) --no-subprojects + clean: - $(GPRCLEAN) -Parun.gpr + $(GPRCLEAN) -p$(GPRFILE) rm -f src/arun-resources.c -.PHONY: all clean prepare run +.PHONY: all clean prepare run doc diff --git a/arun.glade b/arun.glade index 7e21be0..3d634d8 100644 --- a/arun.glade +++ b/arun.glade @@ -2,7 +2,6 @@ - 400 False @@ -39,7 +38,6 @@ edit-find-symbolic False False - Enter a command to run diff --git a/src/arun-handlers.adb b/src/arun-handlers.adb index f0d0615..70bc5b4 100644 --- a/src/arun-handlers.adb +++ b/src/arun-handlers.adb @@ -96,7 +96,6 @@ package body Arun.Handlers is use Ada.Text_IO; use Gdk.Types; use Gdk.Types.Keysyms; - begin if Event.Keyval = GDK_Tab then diff --git a/src/arun-launchers-unix.adb b/src/arun-launchers-unix.adb index 0b5ffe5..50ee198 100644 --- a/src/arun-launchers-unix.adb +++ b/src/arun-launchers-unix.adb @@ -22,6 +22,7 @@ with Ada.Text_IO; use Ada.Text_IO; with Ada.Command_Line.Environment; with Ada.Environment_Variables; +with GNAT.Directory_Operations; with GNAT.OS_Lib; with GNAT.String_Split; with Interfaces.C; @@ -38,7 +39,6 @@ package body Arun.Launchers.Unix is begin Create (L.Path_Components, PATH, Separator, Single); - L.Initialized := True; end Initialize; @@ -118,4 +118,42 @@ package body Arun.Launchers.Unix is end if; end Execute; + + function Discover_Executables (L : in UnixLauncher) return Arun.String_Vectors.Vector is + use GNAT.Directory_Operations; + use GNAT.OS_Lib; + use GNAT.String_Split; + use Ada.Strings.Unbounded; + + Dir : Dir_Type; + File_Name : String (1 .. MAX_FILENAME_LENGTH); + File_Index : Natural := 0; + Executables : Arun.String_Vectors.Vector; + begin + for Index in 1 .. Slice_Count (L.Path_Components) loop + declare + Path_Dir : constant String := Slice (L.Path_Components, Index); + begin + if Is_Directory (Path_Dir) then + Open (Dir, Path_Dir); + loop + Read (Dir, File_Name, File_Index); + exit when File_Index = 0; + declare + Name : constant String := File_Name (1 .. File_Index); + Full_Path : constant String := Path_Dir & "/" & Name; + begin + if Is_Executable_File (Full_Path) then + Executables.Append (To_Unbounded_String (Name)); + end if; + end; + end loop; + Close (Dir); + end if; + end; + end loop; + return Executables; + end Discover_Executables; + + end Arun.Launchers.Unix; diff --git a/src/arun-launchers-unix.ads b/src/arun-launchers-unix.ads index b5546b2..60c68cf 100644 --- a/src/arun-launchers-unix.ads +++ b/src/arun-launchers-unix.ads @@ -22,6 +22,9 @@ with Arun; with GNAT.String_Split; package Arun.Launchers.Unix is + + MAX_FILENAME_LENGTH : constant := 255; + type UnixLauncher is new Arun.Launcher_Type with private; procedure Initialize (L : in out UnixLauncher); @@ -40,6 +43,8 @@ package Arun.Launchers.Unix is -- Execute a command using the given UnixLauncher with an "Argv" -- Slice_Set assuming the first argument is the command and subsequent values -- are arguments for that command. + + function Discover_Executables (L : in UnixLauncher) return Arun.String_Vectors.Vector; private type UnixLauncher is new Arun.Launcher_Type with record diff --git a/src/arun-view.adb b/src/arun-view.adb index 27a8d64..c786135 100644 --- a/src/arun-view.adb +++ b/src/arun-view.adb @@ -19,6 +19,7 @@ with Gtk.Widget; use Gtk.Widget; +with Ada.Text_IO; package body Arun.View is diff --git a/src/arun.adb b/src/arun.adb index 7751384..58dc5d5 100644 --- a/src/arun.adb +++ b/src/arun.adb @@ -18,9 +18,14 @@ ------------------------------------------------------------------------------ with Gtk.Widget; use Gtk.Widget; +with Gtk.GEntry; +with Gtk.Entry_Completion; +with Gtk.Tree_Model; +with Gtk.List_Store; with Glib; use Glib; with Glib.Error; use Glib.Error; +with Glib.Values; with Gtk.Main; use Gtk.Main; with Gtkada.Builder; use Gtkada.Builder; @@ -28,7 +33,20 @@ with Ada.Text_IO; with Arun.Handlers; with Arun.View; +with GNAT.OS_Lib; +with GNAT.Directory_Operations; +with Ada.Strings.Unbounded; + package body Arun is + + function Compare_Strings (Left : in Ada.Strings.Unbounded.Unbounded_String; + Right : in Ada.Strings.Unbounded.Unbounded_String) return Boolean is + use Ada.Strings.Unbounded; + begin + return Left = Right; + end Compare_Strings; + + procedure Main is use Ada.Text_IO; use Gtkada.Builder; @@ -69,8 +87,32 @@ package body Arun is -- Connect commandEntry specific signals declare - Command_Entry : Gtk_Widget := Builder.From_Object ("commandEntry"); + use Gtk.Entry_Completion; + use Gtk.List_Store; + use Gtk.Tree_Model; + use Ada.Strings.Unbounded; + + Completion_Types : constant GType_Array (1 .. 1) := (1 => GType_String); + Items : Gtk_List_Store := Gtk_List_Store_Newv (Types => Completion_Types); + Iter : Gtk_Tree_Iter; + Command_Entry : Gtk.GEntry.Gtk_Entry := Gtk.GEntry.Gtk_Entry (Builder.From_Object ("commandEntry")); + Command_Completion : aliased Gtk_Entry_Completion := Gtk_Entry_Completion_New; + + Completion_String : Glib.Values.GValue; + Executables : String_Vectors.Vector := Builder.Launcher.Discover_Executables; begin + for Element of Executables loop + Items.Append (Iter); + Glib.Values.Init_Set_String (Completion_String, + To_String (Element)); + Items.Set_Value (Iter, 0, Completion_String); + end loop; + + Command_Completion.Set_Model (Items.To_Interface); + Command_Completion.Set_Text_Column (Column => 0); + Command_Completion.Set_Inline_Completion (True); + Command_Completion.Set_Inline_Selection (True); + Command_Entry.Set_Completion (Completion => Command_Completion); Command_Entry.On_Key_Release_Event (Call => Arun.Handlers.Search_KeyPress'Access, After => False); end; diff --git a/src/arun.ads b/src/arun.ads index 469d7af..e961d27 100644 --- a/src/arun.ads +++ b/src/arun.ads @@ -18,12 +18,18 @@ ------------------------------------------------------------------------------ with GNAT.String_Split; +with Ada.Containers.Vectors; +with Ada.Strings.Unbounded; package Arun is procedure Main; type Launcher_Type is interface; + type Discovered_Executable_Handler is access function (L : in Launcher_Type'Class; + Name : in String; + Full_Path : in String) return Boolean; + procedure Initialize (L : in Launcher_Type'Class) is abstract; -- Launcher_Type-specific initialization routine @@ -39,4 +45,13 @@ package Arun is Argv : in GNAT.String_Split.Slice_Set) is abstract; -- Spawn the Executable in place of the current process + function Compare_Strings (Left : in Ada.Strings.Unbounded.Unbounded_String; + Right : in Ada.Strings.Unbounded.Unbounded_String) return Boolean; + package String_Vectors is new Ada.Containers.Vectors (Index_Type => Natural, + Element_Type => Ada.Strings.Unbounded.Unbounded_String, + "=" => Compare_Strings); + + function Discover_Executables (L : in Launcher_Type) return String_Vectors.Vector is abstract; + -- Discover executables which can be launched by the configured Launcher_Type + end Arun;