private void ProcessFunctionFile(FunctionFileApp app, string fileName)
        {
            try
            {
                if (!File.Exists(fileName)) return;

                DateTime modified;
                if (!app.TryGetFileDate(fileName, out modified)) modified = DateTime.MinValue;

                if (modified == DateTime.MinValue || Math.Abs(File.GetLastWriteTime(fileName).Subtract(modified).TotalSeconds) >= 1.0)
                {
                    var merger = new FileMerger();
                    merger.MergeFile(fileName, false);

                    var fileTitle = Path.GetFileNameWithoutExtension(fileName);

                    var model = new CodeModel.CodeModel(merger.MergedContent, fileName);
                    var funcs = (from f in model.FunctionSignatures
                                 where string.Equals(f.Name, fileTitle, StringComparison.OrdinalIgnoreCase)
                                 select f).ToArray();
                    if (funcs.Length > 0)
                    {
                        foreach (var func in funcs)
                        {
                            app.AddFunction(func.Name, func.Signature);
                        }
                    }
                    else
                    {
                        app.RemoveFunctionIgnoreCase(fileTitle);
                    }

                    foreach (var fn in merger.FileNames)
                    {
                        app.UpdateFile(fn, File.GetLastWriteTime(fn));
                    }
                }
            }
            catch (Exception)
            {
                try
                {
                    // Don't show the error because this is just a non-critical background thread.
                    if (File.Exists(fileName)) app.UpdateFile(fileName, File.GetLastWriteTime(fileName));
                }
                catch (Exception)
                { }
            }
        }
        private void ProcessSourceDir(FunctionFileApp app, string dir, bool root)
        {
            try
            {
                foreach (var fileName in Directory.GetFiles(dir, "*.f*"))
                {
                    if (FunctionFilePattern.IsMatch(fileName)) _filesToProcess.Enqueue(fileName);
                }

                foreach (var subDir in Directory.GetDirectories(dir))
                {
                    _dirsToProcess.Enqueue(new ProcessDir { dir = subDir, root = false });
                }

                if (root) app.WatchDir(dir);
            }
            catch (Exception ex)
            {
                Log.WriteError(ex, "Exception when scanning directory '{0}' for functions.", dir);
            }
        }
        private FunctionFileApp GetCurrentApp()
        {
            var currentApp = ProbeEnvironment.CurrentApp;
            FunctionFileApp app;
            lock (_currentAppLock)
            {
                if (_currentApp == null || _currentApp.Name != currentApp)
                {
                    if (_currentApp != null) _currentApp.OnDeactivate();

                    if ((app = _apps.TryGet(currentApp)) == null)
                    {
                        app = new FunctionFileApp(this, currentApp);
                        _apps[currentApp] = app;
                    }

                    _currentApp = app;
                }
                else app = _currentApp;

            }
            return app;
        }