A spotlight-like search that searches the *contents* of files?

I have a number of searches that I use in KM that interrogate content of a text file. By that I mean as I type it reads from a single text file and then displays any lines that match. I would like to have something similar, but instead of interrogating a single text file, it can read the contents of any text files within a specified directory.

I don't know how processor intensive this might be, as with each key press it would effectively have to open and read a couple of hundred markdown files. Before I start down the path of building something like this, I thought it would be best to ask if there is already something in KM that provides an efficient way to do this, or perhaps someone has built something similar that is reasonably performant?

Any suggestions would be appreciated. Thank you.

That's a cool problem. I will immediately ponder it.

After a half hour of work, I think I have all the pieces working. Now I have to put them together.

How are you react in KM for press each key? Your description suggest that you observe pressing each key and react?
I have program which do such things for one file, but it is written in C, uses curses library and works interactively in terminal window.
It maybe interesting for me to expand it ( just for the fun of coding) but I try to understand your current solution first.
Where this result of searching is presented in your macro as you typing?

Are you asking me or him? It isn't clear who you are talking to.

I can tell from your question that you understand that KM doesn't directly support live keyboard input in the manner that he wants. But it is possible using Hotkeys. I have solved that part of the problem. It's also tricky in KM to support live display dynamic output, but I have also solved that problem, even if it's not as pretty as I would like.

I seem to be dealing with just one final error in my code, "No such file or directory." Sometimes the last bug in a piece of code can take 5 minutes to solve, but sometimes it can take hours.

Sorry @Airy, I didn’t address question.
Generally I’ve asked @Lloydi, because I was wondering how theirs current scripts listening to keyboard events and presenting result immediately in KM ( as I understood the description of problem)
I’m also very interested in your solution from KM point of view.

As Unix practitioner I use grep every day, but of course it is not interactive. There is also fzf and my small project
pipemenu
as interactive, but both are focused on stdin input, not on set of files.

And of course the scale of such solution is interesting, if you have hundred’s of files …

And on your first keypress -- A, for example -- it'll return 100s, maybe 1,000s of lines.

How are you expecting these lines to be displayed? What do you then want to do with them?

The finding bit is easy -- grep -ER "your_pattern" /path/to/folder. It's the before and after that'll need the work!

Also, consider whether there's already an application that does what you want. Obsidian, for example, has a "live" text search over an entire vault or sub-folders, displaying both matching documents and lines, and letting you jump to any match with a single click.

If the live search is not an absolute requirement, BBEdit's free version lets you search (and replace) the contents of text based files in folders from a Disk Browser.

One of the curious features of BBEdit is that not only is it fully AppleScriptable but it is AppleScript recordable. Open Script Editor, click the red record button, perform some actions in BBEdit, go back Script Editor, click Stop recording, and it will show you the AppleScript that will perform the actions.

In theory the matches can be returned to AppleScript, therefore KM.

It would require, however, having BBEdit open in the background...

Okay, I've created a macro that can do this. Bear in mind that this is a prototype with a very poor UI. But it actually works. Sprucing it up is the next step, but this macro shows that it's possible.

There are probably more than ten "problems" with this prototype, which are all fixable. Read this brief list of problems before ever attempting to run this macro:

  1. It has to be turned on and off manually. If you fail to turn it off manually after testing it, your keyboard will essentially be dead. So if you aren't adept with turning macros off, don't try it!!! Hey, this macro isn't made for average people to test it out, so don't test it if you don't know how to disable it! I didn't decide upon a way to activate and deactivate this macro, partially because the original poster didn't say how he wanted to do that. ---> I added a screenshot at the bottom of this post so you can see what it looks like without having to run it. <----
  2. It is triggered by the KM Hotkey trigger, for all 26 letters of the alphabet, plus the Space key. I also decided to use the End key as the trigger to clear the search buffer, but that doesn't terminate the macro. As I said above, you have to turn off the macro manually.
  3. It uses the Display Clipboard action to display the results of the search. This is not a very pleasant window to use. It should probably be replaced by a Custom HTML window, but as I said, this is a prototype to demonstrate principles. This window is updated every time you add a character to your search string, but it's very fast so that doesn't seem to be a problem.
  4. There is no support for backspacing at this time. That's a feature for a later version.
  5. It uses a case-insensitive search. The user didn't say that he wanted case-sensitive searches so I made no attempt to implement that.
  6. The macro asks you for a folder when it starts. It doesn't memorize the last folder location. That can be added in the future.
  7. If your folder contains subfolders, you will get a minor search error message. No doubt that can be fixed later.
  8. It probably needs a semaphore to prevent duplicate instances.
  9. It uses the Display Progress Bar action to display your current search string. I love this little action. It works quite well for this situation.

Despite all these temporary limitations, it actually works. I was surprised how well it worked.

Filter Files for Text String Macro (v11.0.4)

Filter Files for Text String.kmmacros (17 KB)

Below is a snapshot of the macro in action. Notice how I typed the word SHELLY and as I was typing all the lines from all the files that contained the string that I was typing appeared in the window, updated dynamically. It was extremely quick, essentially dynamic.

But I agree with other people that KM probably isn't the right tool for this job.

1 Like

So, Obsidian has been mentioned and BBEdit, but what I am looking for is a way for me to search the contents of a file, not a filename match, and for me to then select the best match and it then pastes into whatever application is running.

I mentioned that I have a search which looks up the contents of a single text file. This is using the 'Prompt with list from file' macro:

When I make a selection, it pastes:

It's really simple, but then it's looking at just one file.

Currently I have a bunch of text files that all have the same hotkey trigger. I then get the conflict palette and I select from that, but it's not ideal because this list of conflicts will become huge. Secondly, I can't select using arrow keys etc (got to pick with mouse) OR I have to look at the letter that KM suggests to refine my selection. The 'Prompt with list from file' interaction is much easier to use. Also, it means that I have to add a macro each and every time I add a text file, as opposed to it just finding whatever is in the root directory.

I hope that clarifies what I'm after and what I think works really well.

Wow, you really went the extra mile! I will take a look at this as soon as I can to see if it does what I'm after, or can be bent into submission :slight_smile:

The 'Prompt with list from file' macro handles all this.

I have one hotkey that brings up the prompt, then I type and it filters from the list as I type. Eseentially, I was hoping to have something that behaves like this, only it's not looking at a list in a text file but reading the contents of multiple text files in s specified location.

Thanks. I like how you said, "bent into submission," which shows creativity and persistence.

OK, I have been thinking some more, and I've come full circle.

Instead of searching the contents of files, I can instead do this:

  • One macro which runs frequently can build a text file that contains the filepaths of all the files in the root directly.
  • I use the 'Prompt with list from file' macro (reading from that dynamically generated file)
  • I search, it narrows it down and I hit enter to paste (or select with mouse if still too many results)
  • Job done!

It works how I want, there's no manual update/addition of each file. Any time I add a file, I can get it to retrigger the build script. The main thing is that I need to make sure that I save the files with names that are really clear, and that should do it!

I presume you have solved your problem since you didn't ask any specific questions.

I think I may have! I will try this out tomorrow, but I will also take a good look at what you created too. Thank you!

My look at the problem (from the Unix perspective).

I dont knw how many files you want to scan and how big file can analyse KM Action "Prompt wit list from file" but you can just create temporary file (on demand) from all files which you are want to scan but prefixing each line by filename/filepath

The simple solution looks like this:

Select from temp file.kmmacros (3.3 KB)

Of course it may be very large file if you have many input files but on not too big set it should work good.

There are more variants possible:

  • sorting and getting uniq values (show only one entry in each file)
  • prefixing each line by line number
  • selecting line and go to the file (after cut off line, stay only with file name)
  • ...
    The AWK is very good tool

I think you'll find Textcavator 2021 does that:

1 Like

Obsidian searches within the contents of the files, will let you select your best match, and open that match in a tab with the insertion point at the start of the found text.

The best bit is -- if no text is selected in Obsidian than ⌘C copies the entire paragraph the insertion point is in. Which seems to be what you want.

So you should be able to macro Obsidian to open the search, pause until mouse-click, wait a beat for the selected document to load, ⌘C, then return to your original document and paste.

Shame you didn't post that earlier! You could use the same approach, building a temporary file that you then use in the "Prompt" action:

Search Files with Prompt.kmmacros (4.3 KB)

Set the first action to the directory you want to search in, then see if this starts to give you what you want -- main problem as written is that each line starts with the file path, limiting the actual text shown. But we can work on that if the macro sort of does what you want and doesn't kill your machine's performance!

On my slow old iMac it only takes half a second to create the temporary file -- that's scanning 800+ files with a total of 365,000 lines. It's the "Prompt" filtering that takes the time.

1 Like