mirror of
https://github.com/QL-Win/QuickLook.git
synced 2026-01-29 02:06:48 +08:00
Support cli options #1620
https://github.com/QL-Win/QuickLook/wiki/Command-Line
This commit is contained in:
Submodule QuickLook.Common updated: f4beeeacf3...ef476e971f
@@ -168,7 +168,7 @@ public partial class App : Application
|
||||
// second instance: preview this file
|
||||
if (args.Any() && (Directory.Exists(args.First()) || File.Exists(args.First())))
|
||||
{
|
||||
PipeServerManager.SendMessage(PipeMessages.Toggle, args.First());
|
||||
PipeServerManager.SendMessage(PipeMessages.Toggle, args.First(), [.. args.Skip(1)]);
|
||||
}
|
||||
// second instance: duplicate
|
||||
else
|
||||
|
||||
159
QuickLook/Helpers/CommandLineParser.cs
Normal file
159
QuickLook/Helpers/CommandLineParser.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace QuickLook.Helpers;
|
||||
|
||||
public class CommandLineParser
|
||||
{
|
||||
public StringDictionary Values { get; private set; } = [];
|
||||
|
||||
public CommandLineParser(string[] args = null)
|
||||
{
|
||||
args ??= Environment.GetCommandLineArgs();
|
||||
Regex spliter = new(@"^-{1,2}|^/|=|:", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
Regex remover = new(@"^['""]?(.*?)['""]?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
string param = null!;
|
||||
string[] parts;
|
||||
|
||||
foreach (string txt in args)
|
||||
{
|
||||
parts = spliter.Split(txt, 3);
|
||||
|
||||
switch (parts.Length)
|
||||
{
|
||||
case 1:
|
||||
if (param != null)
|
||||
{
|
||||
if (!Values.ContainsKey(param))
|
||||
{
|
||||
parts[0] = remover.Replace(parts[0], "$1");
|
||||
|
||||
Values.Add(param, parts[0]);
|
||||
}
|
||||
param = null!;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (param != null)
|
||||
{
|
||||
if (!Values.ContainsKey(param))
|
||||
{
|
||||
Values.Add(param, "true");
|
||||
}
|
||||
}
|
||||
param = parts[1];
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (param != null)
|
||||
{
|
||||
if (!Values.ContainsKey(param))
|
||||
{
|
||||
Values.Add(param, "true");
|
||||
}
|
||||
}
|
||||
|
||||
param = parts[1];
|
||||
if (!Values.ContainsKey(param))
|
||||
{
|
||||
parts[2] = remover.Replace(parts[2], "$1");
|
||||
Values.Add(param, parts[2]);
|
||||
}
|
||||
|
||||
param = null!;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (param != null)
|
||||
{
|
||||
if (!Values.ContainsKey(param))
|
||||
{
|
||||
Values.Add(param, bool.TrueString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Has(string key) => Values.ContainsKey(key);
|
||||
|
||||
public bool? GetValueBoolean(string key)
|
||||
{
|
||||
bool? ret = null;
|
||||
|
||||
try
|
||||
{
|
||||
string value = Values[key];
|
||||
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
ret = Convert.ToBoolean(value);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int? GetValueInt32(string key)
|
||||
{
|
||||
int? ret = null;
|
||||
|
||||
try
|
||||
{
|
||||
string value = Values[key];
|
||||
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
ret = Convert.ToInt32(value);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public double? GetValueDouble(string key)
|
||||
{
|
||||
double? ret = null;
|
||||
|
||||
try
|
||||
{
|
||||
string value = Values[key];
|
||||
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
ret = Convert.ToDouble(value);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool IsValueBoolean(string key)
|
||||
{
|
||||
return GetValueBoolean(key) ?? false;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Security.Principal;
|
||||
@@ -50,27 +51,25 @@ internal class PipeServerManager : IDisposable
|
||||
{
|
||||
_server = new NamedPipeServerStream(PipeName, PipeDirection.In);
|
||||
|
||||
new Task(() =>
|
||||
_ = Task.Factory.StartNew(() =>
|
||||
{
|
||||
using (var reader = new StreamReader(_server))
|
||||
using var reader = new StreamReader(_server);
|
||||
Debug.WriteLine("PipeManager: Ready");
|
||||
|
||||
while (true)
|
||||
{
|
||||
Debug.WriteLine("PipeManager: Ready");
|
||||
_server.WaitForConnection();
|
||||
var msg = reader.ReadLine();
|
||||
|
||||
while (true)
|
||||
{
|
||||
_server.WaitForConnection();
|
||||
var msg = reader.ReadLine();
|
||||
Debug.WriteLine($"PipeManager: {msg}");
|
||||
|
||||
Debug.WriteLine($"PipeManager: {msg}");
|
||||
// dispatch message
|
||||
if (MessageReceived(msg))
|
||||
return;
|
||||
|
||||
// dispatch message
|
||||
if (MessageReceived(msg))
|
||||
return;
|
||||
|
||||
_server.Disconnect();
|
||||
}
|
||||
_server.Disconnect();
|
||||
}
|
||||
}).Start();
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -83,10 +82,11 @@ internal class PipeServerManager : IDisposable
|
||||
_server = null;
|
||||
}
|
||||
|
||||
public static void SendMessage(string pipeMessage, string path = null)
|
||||
[SuppressMessage("Style", "IDE0063:Use simple 'using' statement")]
|
||||
public static void SendMessage(string pipeMessage, string path = null, string[] options = null)
|
||||
{
|
||||
if (path == null)
|
||||
path = "";
|
||||
path ??= string.Empty;
|
||||
options ??= [];
|
||||
|
||||
try
|
||||
{
|
||||
@@ -96,7 +96,7 @@ internal class PipeServerManager : IDisposable
|
||||
|
||||
using (var writer = new StreamWriter(client))
|
||||
{
|
||||
writer.WriteLine($"{pipeMessage}|{path}");
|
||||
writer.WriteLine($"{pipeMessage}|{path}|{string.Join(",", options)}");
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
@@ -109,8 +109,8 @@ internal class PipeServerManager : IDisposable
|
||||
|
||||
private bool MessageReceived(string msg)
|
||||
{
|
||||
var split = msg.IndexOf('|');
|
||||
if (split == -1)
|
||||
var split = msg.Split('|');
|
||||
if (split.Length <= 1)
|
||||
return false;
|
||||
|
||||
if (_lastOperation != null && _lastOperation.Status == DispatcherOperationStatus.Pending)
|
||||
@@ -119,10 +119,11 @@ internal class PipeServerManager : IDisposable
|
||||
Debug.WriteLine("Dispatcher task canceled");
|
||||
}
|
||||
|
||||
var wParam = msg.Substring(0, split);
|
||||
var lParam = msg.Substring(split + 1, msg.Length - split - 1);
|
||||
var pipeMessage = split[0];
|
||||
var path = split[1];
|
||||
var option = split.Length >= 3 ? split[2] : string.Empty;
|
||||
|
||||
switch (wParam)
|
||||
switch (pipeMessage)
|
||||
{
|
||||
case PipeMessages.RunAndClose:
|
||||
Application.Current.Dispatcher.BeginInvoke(
|
||||
@@ -132,19 +133,19 @@ internal class PipeServerManager : IDisposable
|
||||
|
||||
case PipeMessages.Invoke:
|
||||
_lastOperation = Application.Current.Dispatcher.BeginInvoke(
|
||||
new Action(() => ViewWindowManager.GetInstance().InvokePreview(lParam)),
|
||||
new Action(() => ViewWindowManager.GetInstance().InvokePreview(path)),
|
||||
DispatcherPriority.ApplicationIdle);
|
||||
return false;
|
||||
|
||||
case PipeMessages.Switch:
|
||||
_lastOperation = Application.Current.Dispatcher.BeginInvoke(
|
||||
new Action(() => ViewWindowManager.GetInstance().SwitchPreview(lParam)),
|
||||
new Action(() => ViewWindowManager.GetInstance().SwitchPreview(path)),
|
||||
DispatcherPriority.ApplicationIdle);
|
||||
return false;
|
||||
|
||||
case PipeMessages.Toggle:
|
||||
_lastOperation = Application.Current.Dispatcher.BeginInvoke(
|
||||
new Action(() => ViewWindowManager.GetInstance().TogglePreview(lParam)),
|
||||
new Action(() => ViewWindowManager.GetInstance().TogglePreview(path, option)),
|
||||
DispatcherPriority.ApplicationIdle);
|
||||
return false;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
using QuickLook.Common.Helpers;
|
||||
using QuickLook.Common.Plugin;
|
||||
using QuickLook.Helpers;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
@@ -73,12 +74,15 @@ internal class ViewWindowManager : IDisposable
|
||||
_viewerWindow.Close();
|
||||
}
|
||||
|
||||
public void TogglePreview(string path = null)
|
||||
public void TogglePreview(string path = null, string options = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
path = NativeMethods.QuickLook.GetCurrentSelection();
|
||||
|
||||
if (_viewerWindow.Visibility == Visibility.Visible && (string.IsNullOrEmpty(path) || path == _invokedPath))
|
||||
if (options != null)
|
||||
InvokePreviewWithOption(path, options);
|
||||
else
|
||||
if (_viewerWindow.Visibility == Visibility.Visible && (string.IsNullOrEmpty(path) || path == _invokedPath))
|
||||
ClosePreview();
|
||||
else
|
||||
InvokePreview(path);
|
||||
@@ -117,6 +121,26 @@ internal class ViewWindowManager : IDisposable
|
||||
InvokePreview(path);
|
||||
}
|
||||
|
||||
public void InvokePreviewWithOption(string path = null, string options = null)
|
||||
{
|
||||
InvokePreview(path);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options)) return;
|
||||
|
||||
var cli = new CommandLineParser(options.Split(','));
|
||||
|
||||
if (cli.Has("top"))
|
||||
{
|
||||
_viewerWindow.Topmost = true;
|
||||
_viewerWindow.buttonTop.Tag = "Top";
|
||||
}
|
||||
if (cli.Has("pin"))
|
||||
{
|
||||
_viewerWindow.Pinned = true;
|
||||
ForgetCurrentWindow();
|
||||
}
|
||||
}
|
||||
|
||||
public void InvokePreview(string path = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
|
||||
Reference in New Issue
Block a user