diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index c1a7f2639..29aef88fd 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -78,7 +78,6 @@ namespace Flow.Launcher.ViewModel _userSelectedRecord = _userSelectedRecordStorage.Load(); _topMostRecord = _topMostRecordStorage.Load(); - InitializeKeyCommands(); ContextMenu = new ResultsViewModel(Settings) { @@ -168,160 +167,164 @@ namespace Flow.Launcher.ViewModel } } - - - private void InitializeKeyCommands() + [RelayCommand] + private async Task ReloadPluginDataAsync() { - EscCommand = new RelayCommand(_ => + Hide(); + + await PluginManager.ReloadDataAsync().ConfigureAwait(false); + Notification.Show(InternationalizationManager.Instance.GetTranslation("success"), InternationalizationManager.Instance.GetTranslation("completedSuccessfully")); + } + [RelayCommand] + private void LoadHistory() + { + if (SelectedIsFromQueryResults()) { - if (!SelectedIsFromQueryResults()) - { - SelectedResults = Results; - } - else - { - Hide(); - } - }); - - ClearQueryCommand = new RelayCommand(_ => + SelectedResults = History; + History.SelectedIndex = _history.Items.Count - 1; + } + else { - if (!string.IsNullOrEmpty(QueryText)) - { - ChangeQueryText(string.Empty); - - // Push Event to UI SystemQuery has changed - //OnPropertyChanged(nameof(SystemQueryText)); - } - }); - - SelectNextItemCommand = new RelayCommand(_ => { SelectedResults.SelectNextResult(); }); - - SelectPrevItemCommand = new RelayCommand(_ => { SelectedResults.SelectPrevResult(); }); - - SelectNextPageCommand = new RelayCommand(_ => { SelectedResults.SelectNextPage(); }); - - SelectPrevPageCommand = new RelayCommand(_ => { SelectedResults.SelectPrevPage(); }); - - SelectFirstResultCommand = new RelayCommand(_ => SelectedResults.SelectFirstResult()); - - StartHelpCommand = new RelayCommand(_ => + SelectedResults = Results; + } + } + [RelayCommand] + private void LoadContextMenu() + { + if (SelectedIsFromQueryResults()) { - PluginManager.API.OpenUrl("https://github.com/Flow-Launcher/Flow.Launcher/wiki/Flow-Launcher/"); - }); - OpenSettingCommand = new RelayCommand(_ => { App.API.OpenSettingDialog(); }); - OpenResultCommand = new AsyncRelayCommand(async _ => + // When switch to ContextMenu from QueryResults, but no item being chosen, should do nothing + // i.e. Shift+Enter/Ctrl+O right after Alt + Space should do nothing + if (SelectedResults.SelectedItem != null) + SelectedResults = ContextMenu; + } + else { - var results = SelectedResults; + SelectedResults = Results; + } + } + [RelayCommand] + private void Backspace(object index) + { + var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.NonGlobalPlugins); - var result = results.SelectedItem?.Result; - if (result == null) + // GetPreviousExistingDirectory does not require trailing '\', otherwise will return empty string + var path = FilesFolders.GetPreviousExistingDirectory((_) => true, query.Search.TrimEnd('\\')); + + var actionKeyword = string.IsNullOrEmpty(query.ActionKeyword) ? string.Empty : $"{query.ActionKeyword} "; + + ChangeQueryText($"{actionKeyword}{path}"); + } + [RelayCommand] + private void AutocompleteQuery() + { + var result = SelectedResults.SelectedItem?.Result; + if (result != null && SelectedIsFromQueryResults()) // SelectedItem returns null if selection is empty. + { + var autoCompleteText = result.Title; + + if (!string.IsNullOrEmpty(result.AutoCompleteText)) { - return; + autoCompleteText = result.AutoCompleteText; } - var hideWindow = await result.ExecuteAsync(new ActionContext + else if (!string.IsNullOrEmpty(SelectedResults.SelectedItem?.QuerySuggestionText)) + { + autoCompleteText = SelectedResults.SelectedItem.QuerySuggestionText; + } + + var specialKeyState = GlobalHotkey.CheckModifiers(); + if (specialKeyState.ShiftPressed) + { + autoCompleteText = result.SubTitle; + } + + ChangeQueryText(autoCompleteText); + } + } + [RelayCommand] + private async Task OpenResultAsync(string index) + { + var results = SelectedResults; + if (index is not null) + { + results.SelectedIndex = int.Parse(index); + } + var result = results.SelectedItem?.Result; + if (result == null) + { + return; + } + var hideWindow = await result.ExecuteAsync(new ActionContext { SpecialKeyState = GlobalHotkey.CheckModifiers() - }).ConfigureAwait(false); + }) + .ConfigureAwait(false); - if (hideWindow) - { - Hide(); - } - - if (SelectedIsFromQueryResults()) - { - _userSelectedRecord.Add(result); - _history.Add(result.OriginQuery.RawQuery); - } - else - { - SelectedResults = Results; - } - }); - - AutocompleteQueryCommand = new RelayCommand(_ => - { - var result = SelectedResults.SelectedItem?.Result; - if (result != null && SelectedIsFromQueryResults()) // SelectedItem returns null if selection is empty. - { - var autoCompleteText = result.Title; - - if (!string.IsNullOrEmpty(result.AutoCompleteText)) - { - autoCompleteText = result.AutoCompleteText; - } - else if (!string.IsNullOrEmpty(SelectedResults.SelectedItem?.QuerySuggestionText)) - { - autoCompleteText = SelectedResults.SelectedItem.QuerySuggestionText; - } - - var specialKeyState = GlobalHotkey.CheckModifiers(); - if (specialKeyState.ShiftPressed) - { - autoCompleteText = result.SubTitle; - } - - ChangeQueryText(autoCompleteText); - } - }); - - BackspaceCommand = new RelayCommand(index => - { - var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.NonGlobalPlugins); - - // GetPreviousExistingDirectory does not require trailing '\', otherwise will return empty string - var path = FilesFolders.GetPreviousExistingDirectory((_) => true, query.Search.TrimEnd('\\')); - - var actionKeyword = string.IsNullOrEmpty(query.ActionKeyword) ? string.Empty : $"{query.ActionKeyword} "; - - ChangeQueryText($"{actionKeyword}{path}"); - }); - - LoadContextMenuCommand = new RelayCommand(_ => - { - if (SelectedIsFromQueryResults()) - { - // When switch to ContextMenu from QueryResults, but no item being chosen, should do nothing - // i.e. Shift+Enter/Ctrl+O right after Alt + Space should do nothing - if (SelectedResults.SelectedItem != null) - SelectedResults = ContextMenu; - } - else - { - SelectedResults = Results; - } - }); - - LoadHistoryCommand = new RelayCommand(_ => - { - if (SelectedIsFromQueryResults()) - { - SelectedResults = History; - History.SelectedIndex = _history.Items.Count - 1; - } - else - { - SelectedResults = Results; - } - }); - - ReloadPluginDataCommand = new RelayCommand(_ => + if (hideWindow) { Hide(); + } - _ = PluginManager - .ReloadDataAsync() - .ContinueWith(_ => - Application.Current.Dispatcher.Invoke(() => - { - Notification.Show( - InternationalizationManager.Instance.GetTranslation("success"), - InternationalizationManager.Instance.GetTranslation("completedSuccessfully") - ); - }), TaskScheduler.Default) - .ConfigureAwait(false); - }); + if (SelectedIsFromQueryResults()) + { + _userSelectedRecord.Add(result); + _history.Add(result.OriginQuery.RawQuery); + } + else + { + SelectedResults = Results; + } + } + [RelayCommand] + private void OpenSetting() + { + App.API.OpenSettingDialog(); + } + + [RelayCommand] + private void SelectHelp() + { + PluginManager.API.OpenUrl("https://www.flowlauncher.com/docs/#/usage-tips"); + } + + [RelayCommand] + private void SelectFirstResult() + { + SelectedResults.SelectFirstResult(); + } + [RelayCommand] + private void SelectPrevPage() + { + SelectedResults.SelectPrevPage(); + } + + [RelayCommand] + private void SelectNextPage() + { + SelectedResults.SelectNextPage(); + } + [RelayCommand] + private void SelectPrevItem() + { + SelectedResults.SelectPrevResult(); + } + [RelayCommand] + private void SelectNextItem() + { + SelectedResults.SelectNextResult(); + } + + [RelayCommand] + private void Esc() + { + if (!SelectedIsFromQueryResults()) + { + SelectedResults = Results; + } + else + { + Hide(); + } } #endregion @@ -418,6 +421,7 @@ namespace Flow.Launcher.ViewModel /// but we don't want to move cursor to end when query is updated from TextBox /// /// + /// Force query even when Query Text doesn't change public void ChangeQueryText(string queryText, bool reQuery = false) { if (QueryText != queryText) @@ -496,25 +500,6 @@ namespace Flow.Launcher.ViewModel public string PluginIconPath { get; set; } = null; - public ICommand EscCommand { get; set; } - public ICommand BackspaceCommand { get; set; } - public ICommand SelectNextItemCommand { get; set; } - public ICommand SelectPrevItemCommand { get; set; } - public ICommand SelectNextPageCommand { get; set; } - public ICommand SelectPrevPageCommand { get; set; } - public ICommand SelectFirstResultCommand { get; set; } - public ICommand StartHelpCommand { get; set; } - public ICommand LoadContextMenuCommand { get; set; } - public ICommand LoadHistoryCommand { get; set; } - public ICommand OpenResultCommand { get; set; } - public ICommand OpenSettingCommand { get; set; } - public ICommand ReloadPluginDataCommand { get; set; } - public ICommand ClearQueryCommand { get; private set; } - - public ICommand CopyToClipboard { get; set; } - - public ICommand AutocompleteQueryCommand { get; set; } - public string OpenResultCommandModifiers { get; private set; } public string Image => Constant.QueryTextBoxIconImagePath; diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs index 72b7b0a91..b93fb23c9 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs @@ -97,8 +97,8 @@ namespace Flow.Launcher.Plugin.Program.Programs } // To initialize the app description - public String description = String.Empty; - + public string description = string.Empty; + public string arguments = string.Empty; // Retrieve the target path using Shell Link public string retrieveTargetPath(string path) @@ -122,13 +122,16 @@ namespace Flow.Launcher.Plugin.Program.Programs buffer = new StringBuilder(MAX_PATH); ((IShellLinkW)link).GetDescription(buffer, MAX_PATH); description = buffer.ToString(); + + buffer.Clear(); + ((IShellLinkW)link).GetArguments(buffer, MAX_PATH); + arguments = buffer.ToString(); } // To release unmanaged memory Marshal.ReleaseComObject(link); return target; - } } -} \ No newline at end of file +} diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index d973185b2..7fbffb548 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -26,11 +26,11 @@ namespace Flow.Launcher.Plugin.Program.Programs public string UniqueIdentifier { get => _uid; set => _uid = value == null ? string.Empty : value.ToLowerInvariant(); } // For path comparison public string IcoPath { get; set; } /// - /// Path of the file. It's the path of .lnk or .url for .lnk and .url. + /// Path of the file. It's the path of .lnk and .url for .lnk and .url files. /// public string FullPath { get; set; } /// - /// Path of the excutable for .lnk, or the URL for .url. + /// Path of the excutable for .lnk, or the URL for .url. Arguments are included if any. /// public string LnkResolvedPath { get; set; } /// @@ -185,7 +185,7 @@ namespace Flow.Launcher.Plugin.Program.Programs { var info = new ProcessStartInfo { - FileName = ExecutablePath, + FileName = FullPath, WorkingDirectory = ParentDirectory, Verb = "runas", UseShellExecute = true @@ -275,6 +275,12 @@ namespace Flow.Launcher.Plugin.Program.Programs program.LnkResolvedPath = Path.GetFullPath(target); program.ExecutableName = Path.GetFileName(target); + var args = _helper.arguments; + if(!string.IsNullOrEmpty(args)) + { + program.LnkResolvedPath += " " + args; + } + var description = _helper.description; if (!string.IsNullOrEmpty(description)) {