Packages
fnord
0.4.4
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
221 Versions
Jump to
Current section
221 Versions
Compare versions
5
files changed
+109
additions
-5
deletions
| @@ -49,6 +49,12 @@ You can **reindex** the project, forcing it to reindex all files: | |
| 49 49 | fnord index --project foo --dir /path/to/foo --reindex |
| 50 50 | ``` |
| 51 51 | |
| 52 | + You can also watch the project for changes and reindex them as they happen: |
| 53 | + |
| 54 | + ```bash |
| 55 | + fnord watch --project foo --dir /path/to/foo |
| 56 | + ``` |
| 57 | + |
| 52 58 | ### Searching |
| 53 59 | |
| 54 60 | ```bash |
| @@ -72,6 +78,4 @@ Note that deleting a project only deletes from the index, not the actual files. | |
| 72 78 | |
| 73 79 | ## TODO |
| 74 80 | |
| 75 | - - Daemon mode that watches for file changes and updates the index |
| 76 | - - Handle deleted files |
| 77 81 | - Progress bar |
| @@ -1,6 +1,6 @@ | |
| 1 1 | {<<"links">>,[{<<"GitHub">>,<<"https://github.com/sysread/fnord">>}]}. |
| 2 2 | {<<"name">>,<<"fnord">>}. |
| 3 | - {<<"version">>,<<"0.4.3">>}. |
| 3 | + {<<"version">>,<<"0.4.4">>}. |
| 4 4 | {<<"description">>, |
| 5 5 | <<"Index and search your code base with OpenAI's embeddings API">>}. |
| 6 6 | {<<"elixir">>,<<"~> 1.17">>}. |
| @@ -29,7 +29,7 @@ | |
| 29 29 | {<<"repository">>,<<"hexpm">>}]]}. |
| 30 30 | {<<"files">>, |
| 31 31 | [<<"lib">>,<<"lib/ai.ex">>,<<"lib/store.ex">>,<<"lib/queue.ex">>, |
| 32 | - <<"lib/git.ex">>,<<"lib/scanner.ex">>,<<"lib/fnord.ex">>, |
| 32 | + <<"lib/git.ex">>,<<"lib/scanner.ex">>,<<"lib/watch.ex">>,<<"lib/fnord.ex">>, |
| 33 33 | <<"lib/summary.ex">>,<<"lib/indexer.ex">>,<<"lib/search.ex">>, |
| 34 34 | <<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>]}. |
| 35 35 | {<<"build_tools">>,[<<"mix">>]}. |
| @@ -17,6 +17,7 @@ defmodule Fnord do | |
| 17 17 | :torch -> Indexer.new(opts) |> Indexer.delete_project() |
| 18 18 | :projects -> Store.list_projects() |> Enum.each(&IO.puts(&1)) |
| 19 19 | :files -> Store.new(opts.project) |> Store.list_files() |> Enum.each(&IO.puts(&1)) |
| 20 | + :watch -> Watch.run(opts) |
| 20 21 | end |
| 21 22 | else |
| 22 23 | {:error, reason} -> IO.puts("Error: #{reason}") |
| @@ -93,6 +94,7 @@ defmodule Fnord do | |
| 93 94 | description: "fnord - intelligent code index and search", |
| 94 95 | about: "Index and search code files", |
| 95 96 | allow_unknown_args: false, |
| 97 | + version: get_version(), |
| 96 98 | subcommands: [ |
| 97 99 | projects: [ |
| 98 100 | name: "projects", |
| @@ -145,6 +147,14 @@ defmodule Fnord do | |
| 145 147 | project: project, |
| 146 148 | file: file |
| 147 149 | ] |
| 150 | + ], |
| 151 | + watch: [ |
| 152 | + name: "watch", |
| 153 | + about: "Watch for changes in the project directory using Watchman", |
| 154 | + options: [ |
| 155 | + directory: directory, |
| 156 | + project: project |
| 157 | + ] |
| 148 158 | ] |
| 149 159 | ] |
| 150 160 | ) |
| @@ -160,4 +170,9 @@ defmodule Fnord do | |
| 160 170 | _ -> {:error, "missing or unknown subcommand"} |
| 161 171 | end |
| 162 172 | end |
| 173 | + |
| 174 | + defp get_version do |
| 175 | + {:ok, vsn} = :application.get_key(:fnord, :vsn) |
| 176 | + to_string(vsn) |
| 177 | + end |
| 163 178 | end |
| @@ -0,0 +1,85 @@ | |
| 1 | + defmodule Watch do |
| 2 | + @moduledoc """ |
| 3 | + Watch a directory for changes and run the fnord index command when changes |
| 4 | + are detected. |
| 5 | + """ |
| 6 | + |
| 7 | + def run(opts) do |
| 8 | + with :ok <- check_dependencies() do |
| 9 | + cmd("watchman", ["watch", opts.directory]) |
| 10 | + cmd("watchman", ["--log-level", "info"]) |
| 11 | + |
| 12 | + IO.puts("Watching #{opts.directory} for changes") |
| 13 | + setup_trigger(opts.directory, opts.project) |
| 14 | + |
| 15 | + IO.puts("Press Ctrl+C to stop watching") |
| 16 | + wait_for_changes() |
| 17 | + end |
| 18 | + end |
| 19 | + |
| 20 | + defp cmd(command, args) do |
| 21 | + IO.puts("> #{command} #{Enum.join(args, " ")}") |
| 22 | + System.cmd(command, args, stderr_to_stdout: true) |
| 23 | + end |
| 24 | + |
| 25 | + defp shell(command) do |
| 26 | + IO.puts("> #{command}") |
| 27 | + System.shell(command) |
| 28 | + end |
| 29 | + |
| 30 | + defp check_dependencies do |
| 31 | + case System.find_executable("watchman") do |
| 32 | + nil -> {:error, "Watchman is required to run this module. Please install it and try again."} |
| 33 | + _ -> :ok |
| 34 | + end |
| 35 | + end |
| 36 | + |
| 37 | + defp setup_trigger(directory, project) do |
| 38 | + command_json = |
| 39 | + Jason.encode!([ |
| 40 | + "trigger", |
| 41 | + directory, |
| 42 | + %{ |
| 43 | + "name" => "fnord-trigger", |
| 44 | + "expression" => ["true"], |
| 45 | + "command" => ["fnord", "index", "-p", project, "-d", directory], |
| 46 | + "settle" => 5_000 |
| 47 | + } |
| 48 | + ]) |
| 49 | + |
| 50 | + shell("watchman -j <<EOF\n#{command_json}\nEOF") |
| 51 | + end |
| 52 | + |
| 53 | + defp wait_for_changes do |
| 54 | + log_path = |
| 55 | + cmd("watchman", ["get-log"]) |
| 56 | + |> elem(0) |
| 57 | + |> Jason.decode!() |
| 58 | + |> get_in(["log"]) |
| 59 | + |
| 60 | + IO.puts("> tail -f #{log_path}") |
| 61 | + |
| 62 | + # Open a port to execute `tail -f` and stream the output to the console |
| 63 | + port = |
| 64 | + Port.open({:spawn_executable, System.find_executable("tail")}, [ |
| 65 | + :exit_status, |
| 66 | + :stderr_to_stdout, |
| 67 | + :stream, |
| 68 | + args: ["-f", log_path] |
| 69 | + ]) |
| 70 | + |
| 71 | + # Continuously read from the port and print output to the console |
| 72 | + listen_to_port(port) |
| 73 | + end |
| 74 | + |
| 75 | + defp listen_to_port(port) do |
| 76 | + receive do |
| 77 | + {^port, {:data, data}} -> |
| 78 | + IO.write(data) |
| 79 | + listen_to_port(port) |
| 80 | + |
| 81 | + {^port, {:exit_status, status}} -> |
| 82 | + IO.puts("tail process exited with status: #{status}") |
| 83 | + end |
| 84 | + end |
| 85 | + end |
| @@ -4,7 +4,7 @@ defmodule Fnord.MixProject do | |
| 4 4 | def project do |
| 5 5 | [ |
| 6 6 | app: :fnord, |
| 7 | - version: "0.4.3", |
| 7 | + version: "0.4.4", |
| 8 8 | elixir: "~> 1.17", |
| 9 9 | start_permanent: Mix.env() == :prod, |
| 10 10 | description: "Index and search your code base with OpenAI's embeddings API", |