Esempio n. 1
0
        public SearchHints(IRecentSearchCollection recentSearchCollection, ISchedulerProvider schedulerProvider)
        {
            //User feedback to guide them whilst typing
            var searchText = this.WhenValueChanged(vm => vm.SearchText);
            var useRegEx   = this.WhenValueChanged(vm => vm.UseRegex);

            //if regex then validate

            var combined = searchText.CombineLatest(useRegEx, (text, regex) => new SearchRequest(text, regex))
                           .Throttle(TimeSpan.FromMilliseconds(250))
                           .Select(searchRequest => searchRequest.BuildMessage())
                           .Publish();

            IsValid = combined.Select(shm => shm.IsValid).DistinctUntilChanged().ForBinding();
            Message = combined.Select(shm => shm.Message).DistinctUntilChanged().ForBinding();

            var forceRefreshOfError = combined.Select(shm => shm.IsValid)
                                      .DistinctUntilChanged()
                                      .Subscribe(_ =>
            {
                this.OnPropertyChanged("SearchText");
            });

            var predictRegex = this.WhenValueChanged(vm => vm.SearchText)
                               .Select(text => _regexInspector.DoesThisLookLikeRegEx(text))
                               .Subscribe(likeRegex => UseRegex = likeRegex);

            //Handle adding new search
            var searchRequested = new Subject <SearchRequest>();

            SearchRequested  = searchRequested.AsObservable();
            AddSearchCommand = new Command(async() =>
            {
                await Task.Run(() =>
                {
                    recentSearchCollection.Add(new RecentSearch(SearchText));
                    searchRequested.OnNext(new SearchRequest(SearchText, UseRegex));
                    SearchText = string.Empty;
                    UseRegex   = false;
                });
            }, () => IsValid.Value && SearchText.Length > 0);


            var dataLoader = recentSearchCollection.Items.Connect()
                             // .Filter(filter)
                             .Transform(recentSearch => recentSearch.Text)
                             .Sort(SortExpressionComparer <string> .Ascending(str => str))
                             .ObserveOn(schedulerProvider.MainThread)
                             .Bind(out _hints)
                             .Subscribe();

            _cleanUp = new CompositeDisposable(IsValid, Message, predictRegex, dataLoader, searchRequested.SetAsComplete(), combined.Connect(), forceRefreshOfError);
        }
Esempio n. 2
0
        public SearchHints(IRecentSearchCollection recentSearchCollection, ISchedulerProvider schedulerProvider)
        {
            //User feedback to guide them whilst typing
            var searchText = this.WhenValueChanged(vm => vm.SearchText);
            var useRegEx = this.WhenValueChanged(vm => vm.UseRegex);

            //if regex then validate

            var combined = searchText.CombineLatest(useRegEx, (text, regex) => new SearchRequest(text, regex))
                .Throttle(TimeSpan.FromMilliseconds(250))
                .Select(searchRequest => searchRequest.BuildMessage())
                .Publish();

            IsValid = combined.Select(shm => shm.IsValid).DistinctUntilChanged().ForBinding();
            Message = combined.Select(shm => shm.Message).DistinctUntilChanged().ForBinding();

            var forceRefreshOfError = combined.Select(shm => shm.IsValid)
                .DistinctUntilChanged()
                .Subscribe(_ =>
                {
                    this.OnPropertyChanged("SearchText");
                });

            var predictRegex = this.WhenValueChanged(vm => vm.SearchText)
                                        .Select(text => _regexInspector.DoesThisLookLikeRegEx(text))
                                        .Subscribe(likeRegex => UseRegex = likeRegex);

            //Handle adding new search
            var searchRequested = new Subject<SearchRequest>();
            SearchRequested = searchRequested.AsObservable();
            AddSearchCommand = new Command(async () =>
            {
                await Task.Run(() =>
                {
                    recentSearchCollection.Add(new RecentSearch(SearchText));
                    searchRequested.OnNext(new SearchRequest(SearchText, UseRegex));
                    SearchText = string.Empty;
                    UseRegex = false;
                });

            }, () => IsValid.Value && SearchText.Length > 0);

            var dataLoader = recentSearchCollection.Items.Connect()
                // .Filter(filter)
                .Transform(recentSearch => recentSearch.Text)
                .Sort(SortExpressionComparer<string>.Ascending(str => str))
                .ObserveOn(schedulerProvider.MainThread)
                .Bind(out _hints)
                .Subscribe();

            _cleanUp = new CompositeDisposable(IsValid, Message, predictRegex, dataLoader, searchRequested.SetAsComplete(), combined.Connect(), forceRefreshOfError);
        }
Esempio n. 3
0
        public SearchHints(IRecentSearchCollection recentSearchCollection, ISchedulerProvider schedulerProvider)
        {
            //build a predicate when SearchText changes
            var filter = this.WhenValueChanged(t => t.SearchText)
                .Throttle(TimeSpan.FromMilliseconds(250))
                .Select(BuildFilter);

            //User feedback to guide them whilst typing
            var searchText = this.WhenValueChanged(vm => vm.SearchText);
            var useRegEx = this.WhenValueChanged(vm => vm.UseRegex);

            //if regex then validate

            var combined = searchText.CombineLatest(useRegEx, (text, regex) => new SearchRequest(text, regex))
                .Publish();



            IsValid = combined.Select(searchRequest => searchRequest.BuildMessage()).ForBinding();
            

            var predictRegex = this.WhenValueChanged(vm => vm.SearchText)
                                        //.Where(text=>!string.IsNullOrEmpty(text))
                                        .Select(text=>_regexInspector.DoesThisLookLikeRegEx(text))
                                       // .DistinctUntilChanged()
                                        .Subscribe(likeRegex=> UseRegex= likeRegex);

            //Handle adding new search
            var searchRequested = new Subject<SearchRequest>();
            SearchRequested = searchRequested.AsObservable();
            AddSearchCommand = new Command(() =>
            {
                recentSearchCollection.Add(new RecentSearch(SearchText));
                searchRequested.OnNext(new SearchRequest(SearchText, UseRegex));
                SearchText = string.Empty;
                UseRegex = false;

            }, () => IsValid.Value.IsValid && SearchText.Length>0);


            var dataLoader = recentSearchCollection.Items.Connect()
                .Filter(filter)  
                .Transform(recentSearch=> recentSearch.Text)
                .Sort(SortExpressionComparer<string>.Ascending(str => str))
                .ObserveOn(schedulerProvider.MainThread)
                .Bind(out _hints) 
                .Subscribe();

            _cleanUp = new CompositeDisposable( dataLoader, IsValid, predictRegex, Disposable.Create(searchRequested.OnCompleted), combined.Connect());
        }
Esempio n. 4
0
        public FileTailerViewModel([NotNull] ILogger logger,
                                   [NotNull] ISchedulerProvider schedulerProvider,
                                   [NotNull] IFileWatcher fileWatcher,
                                   [NotNull] ISelectionMonitor selectionMonitor,
                                   [NotNull] IClipboardHandler clipboardHandler,
                                   [NotNull] ISearchInfoCollection searchInfoCollection,
                                   [NotNull] IInlineViewerFactory inlineViewerFactory,
                                   [NotNull] ISetting <GeneralOptions> generalOptions,
                                   [NotNull] IRecentSearchCollection recentSearchCollection,
                                   [NotNull] SearchHints searchHints)
        {
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (schedulerProvider == null)
            {
                throw new ArgumentNullException(nameof(schedulerProvider));
            }
            if (fileWatcher == null)
            {
                throw new ArgumentNullException(nameof(fileWatcher));
            }
            if (selectionMonitor == null)
            {
                throw new ArgumentNullException(nameof(selectionMonitor));
            }
            if (clipboardHandler == null)
            {
                throw new ArgumentNullException(nameof(clipboardHandler));
            }
            if (searchInfoCollection == null)
            {
                throw new ArgumentNullException(nameof(searchInfoCollection));
            }
            if (inlineViewerFactory == null)
            {
                throw new ArgumentNullException(nameof(inlineViewerFactory));
            }
            if (generalOptions == null)
            {
                throw new ArgumentNullException(nameof(generalOptions));
            }
            if (searchHints == null)
            {
                throw new ArgumentNullException(nameof(searchHints));
            }

            SelectionMonitor       = selectionMonitor;
            SearchHints            = searchHints;
            CopyToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText()));
            SelectedItemsCount     = selectionMonitor.Selected.Connect().QueryWhenChanged(collection => collection.Count).ForBinding();
            SearchCollection       = new SearchCollection(searchInfoCollection, schedulerProvider);

            UsingDarkTheme = generalOptions.Value
                             .ObserveOn(schedulerProvider.MainThread)
                             .Select(options => options.Theme == Theme.Dark)
                             .ForBinding();

            HighlightTail = generalOptions.Value
                            .ObserveOn(schedulerProvider.MainThread)
                            .Select(options => options.HighlightTail)
                            .ForBinding();

            HighlightDuration = generalOptions.Value
                                .ObserveOn(schedulerProvider.MainThread)
                                .Select(options => new Duration(TimeSpan.FromSeconds(options.HighlightDuration)))
                                .ForBinding();

            //An observable which acts as a scroll command
            var autoChanged = this.WhenValueChanged(vm => vm.AutoTail);
            var scroller    = _userScrollRequested.CombineLatest(autoChanged, (user, auto) =>
            {
                var mode = AutoTail ? ScrollReason.Tail : ScrollReason.User;
                return(new ScrollRequest(mode, user.PageSize, user.FirstIndex));
            })
                              .ObserveOn(schedulerProvider.Background)
                              .DistinctUntilChanged();

            //tailer is the main object used to tail, scroll and filter in a file
            var lineScroller = new LineScroller(SearchCollection.Latest.ObserveOn(schedulerProvider.Background), scroller);

            //Add a complete file display [No search info here]
            var indexed = fileWatcher.Latest.Index()
                          .Replay(1).RefCount();

            IsLoading = indexed.Take(1).Select(_ => false).StartWith(true).ForBinding();
            searchInfoCollection.Add("<All>", indexed, SearchType.All);

            //command to add the current search to the tail collection
            KeepSearchCommand = new Command(() =>
            {
                var text   = SearchHints.SearchText;
                var latest = fileWatcher.Latest
                             .Search(s => s.Contains(text, StringComparison.OrdinalIgnoreCase))
                             .Replay(1).RefCount();

                searchInfoCollection.Add(text, latest);
                recentSearchCollection.Add(new RecentSearch(text));
                SearchHints.SearchText = string.Empty;
            }, () => SearchHints.SearchText.IsLongerThanOrEqualTo(3));

            //User feedback to show file size
            FileSizeText = fileWatcher.Latest.Select(fn => fn.Size)
                           .Select(size => size.FormatWithAbbreviation())
                           .DistinctUntilChanged()
                           .ForBinding();

            //User feedback to guide them whilst typing
            SearchHint = this.WhenValueChanged(vm => vm.SearchHints.SearchText)
                         .Select(text =>
            {
                if (string.IsNullOrEmpty(text))
                {
                    return("Type to search");
                }
                return(text.Length < 3 ? "Enter at least 3 characters" : "Hit enter to search");
            }).ForBinding();

            //load lines into observable collection
            var lineProxyFactory = new LineProxyFactory(new TextFormatter(searchInfoCollection));
            var loader           = lineScroller.Lines.Connect()
                                   .Transform(lineProxyFactory.Create, new ParallelisationOptions(ParallelType.Ordered, 5))
                                   .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy))
                                   .ObserveOn(schedulerProvider.MainThread)
                                   .Bind(out _data)
                                   .DisposeMany()
                                   .Subscribe(changes => logger.Info($"Rows changed. {changes.Adds} adds, {changes.Removes} removed"),
                                              ex => logger.Error(ex, "There is a problem with bind data"));

            //monitor matching lines and start index,
            Count       = indexed.Select(latest => latest.Count).ForBinding();
            CountText   = indexed.Select(latest => $"{latest.Count.ToString("##,###")} lines").ForBinding();
            LatestCount = SearchCollection.Latest.Select(latest => latest.Count).ForBinding();

            //track first visible index
            var firstIndexMonitor = lineScroller.Lines.Connect()
                                    .Buffer(TimeSpan.FromMilliseconds(250)).FlattenBufferResult()
                                    .ToCollection()
                                    .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1)
                                    .ObserveOn(schedulerProvider.MainThread)
                                    .Subscribe(first => FirstIndex = first);

            //Create objects required for inline viewing
            var isUserDefinedChanged = SearchCollection.WhenValueChanged(sc => sc.Selected)
                                       .Select(selected => selected.IsUserDefined)
                                       .DistinctUntilChanged();

            var inlineViewerVisible = isUserDefinedChanged.CombineLatest(this.WhenValueChanged(vm => vm.ShowInline),
                                                                         (userDefined, showInline) => userDefined && showInline);

            CanViewInline       = isUserDefinedChanged.ForBinding();
            InlineViewerVisible = inlineViewerVisible.ForBinding();

            //return an empty line provider unless user is viewing inline - this saves needless trips to the file
            var inline = indexed.CombineLatest(inlineViewerVisible, (index, ud) => ud ? index : new EmptyLineProvider());

            InlineViewer = inlineViewerFactory.Create(inline, this.WhenValueChanged(vm => vm.SelectedItem), lineProxyFactory);

            _cleanUp = new CompositeDisposable(lineScroller,
                                               loader,
                                               firstIndexMonitor,
                                               IsLoading,
                                               Count,
                                               LatestCount,
                                               FileSizeText,
                                               SearchHint,
                                               SelectedItemsCount,
                                               CanViewInline,
                                               InlineViewer,
                                               InlineViewerVisible,
                                               SearchCollection,
                                               searchInfoCollection,
                                               HighlightTail,
                                               UsingDarkTheme,
                                               searchHints,
                                               Disposable.Create(() =>
            {
                _userScrollRequested.OnCompleted();
                SelectionMonitor?.Dispose();
            }));
        }