I was tasked with conducting a large number of text searches in the code files of multiple projects. Initially, I just used the Find in Files feature of Visual Studio in a couple of the running instances, but then I realized I needed to search other solutions as well. So I quickly created an F# Script (below) to conduct the searches across all code files async.
For all matching results, the script prints:
C:\path-to-file linenumber: line of code
How can this be improved? The script runs extremely fast and did its job well. Now, out of curiosity, I would like to know what improvements could be made to optimize performance?
open System
open System.IO
let directory = @"C:\path-to-top-level-directory"
// this just keeps async operations from writing to the console concurrently (garbled result)
let agent = MailboxProcessor.Start(fun inbox ->
// the message processing function
let rec messageLoop () = async {
let! msg = inbox.Receive()
printfn "%s" msg
return! messageLoop()
}
// start the loop
messageLoop ()
)
let checkIfContains value file = async {
use reader = new StreamReader(File.OpenRead(file))
let lineNum = ref -1
let postResult (i, s) = sprintf "%s\r\n%i: %s\r\n" file i s |> agent.Post
seq { while not reader.EndOfStream do
incr lineNum
yield (!lineNum, reader.ReadLine()) }
|> Seq.filter (fun (_, s) -> s.Contains(value))
|> Seq.iter postResult
}
let files =
Directory.EnumerateFiles(directory, "*.vb", SearchOption.AllDirectories)
|> Seq.append (Directory.EnumerateFiles(directory, "*.cs", SearchOption.AllDirectories))
while true do
agent.Post "Search string: "
let value = Console.ReadLine()
agent.Post "Searching...\r\n"
files
|> Seq.map (checkIfContains value)
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
agent.Post "\r\nDone.\r\n\r\n"
Console.out
should do) - but hey: that's nitpicking \$\endgroup\$ – Carsten Sep 12 '14 at 19:14grep
. \$\endgroup\$ – John Palmer Sep 13 '14 at 23:36