mirror of
https://github.com/neovide/neovide.git
synced 2026-09-10 07:16:25 -04:00
feat: add ability to open files from Finder in macOS (#2395)
* non-working plist attempt * add Neovide.icns * remove old build attempt * make-icns script * add background for dmg installer * app + dmg builder script * first version of Info.plist * add missing keys from production build * support retina backgrounds with tiff * add lots of types... * also add exported type declarations * consistent quotes * sigh * comment * feat(mac): implement openFiles on macOS * feat: default to fork if in tty * add source image and instructions --------- Co-authored-by: Travis <travis@marketcake.com>
This commit is contained in:
parent
810fb9ac01
commit
fcf5e87bf8
|
|
@ -131,4 +131,3 @@ long_description = """
|
|||
This is a simple graphical user interface for Neovim. Where possible there are some graphical improvements, but it should act functionally like the terminal UI.
|
||||
"""
|
||||
osx_minimum_system_version = "10.11"
|
||||
|
||||
|
|
|
|||
21
assets/dmg-background/README.md
Normal file
21
assets/dmg-background/README.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
### OSX DMG Background
|
||||
|
||||
source.pdf in this directory can be used for modifying the background of the
|
||||
dmg installer on OSX.
|
||||
|
||||
JetBrainsMono can be downloaded from [Nerd Fonts](https://www.nerdfonts.com/font-downloads).
|
||||
|
||||
After any changes, you must export 2 images with the following paths, filenames
|
||||
and dimensions:
|
||||
|
||||
1. `assets/neovide-dmg-background.png` (650x450)
|
||||
2. `assets/neovide-dmg-background@2x.png` (1300x900)
|
||||
|
||||
Next, to support retina images you must generate a properly composed tiff by running the builder script from the root of the project:
|
||||
|
||||
```
|
||||
macos-builder/make-icns
|
||||
```
|
||||
|
||||
This script will also generate an `.icns` file with all the proper sizes from
|
||||
the `assets/neovide-1024.png` source image.
|
||||
BIN
assets/dmg-background/source.pdf
Normal file
BIN
assets/dmg-background/source.pdf
Normal file
Binary file not shown.
BIN
assets/neovide-1024.png
Normal file
BIN
assets/neovide-1024.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
BIN
assets/neovide-dmg-background.png
Normal file
BIN
assets/neovide-dmg-background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
BIN
assets/neovide-dmg-background.tiff
Normal file
BIN
assets/neovide-dmg-background.tiff
Normal file
Binary file not shown.
BIN
assets/neovide-dmg-background@2x.png
Normal file
BIN
assets/neovide-dmg-background@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 330 KiB |
2435
extra/osx/Neovide.app/Contents/Info.plist
Normal file
2435
extra/osx/Neovide.app/Contents/Info.plist
Normal file
File diff suppressed because it is too large
Load diff
BIN
extra/osx/Neovide.app/Contents/Resources/Neovide.icns
Normal file
BIN
extra/osx/Neovide.app/Contents/Resources/Neovide.icns
Normal file
Binary file not shown.
32
macos-builder/make-icns
Executable file
32
macos-builder/make-icns
Executable file
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
ASSETS_DIR="assets"
|
||||
ICONSET_DIR="extra/osx/Neovide.app/Contents/Resources/Neovide.iconset"
|
||||
|
||||
mkdir -p "${ICONSET_DIR}"
|
||||
|
||||
# make tiff (for dmg background to support retina)
|
||||
|
||||
tiffutil \
|
||||
-cathidpicheck \
|
||||
"${ASSETS_DIR}/neovide-dmg-background.png" \
|
||||
"${ASSETS_DIR}/neovide-dmg-background@2x.png" \
|
||||
-out "${ASSETS_DIR}/neovide-dmg-background.tiff"
|
||||
|
||||
# make icns
|
||||
|
||||
sips -z 16 16 "${ASSETS_DIR}/neovide-1024.png" --out "${ICONSET_DIR}/icon_16x16.png"
|
||||
sips -z 32 32 "${ASSETS_DIR}/neovide-1024.png" --out "${ICONSET_DIR}/icon_16x16@2x.png"
|
||||
sips -z 32 32 "${ASSETS_DIR}/neovide-1024.png" --out "${ICONSET_DIR}/icon_32x32.png"
|
||||
sips -z 64 64 "${ASSETS_DIR}/neovide-1024.png" --out "${ICONSET_DIR}/icon_32x32@2x.png"
|
||||
sips -z 128 128 "${ASSETS_DIR}/neovide-1024.png" --out "${ICONSET_DIR}/icon_128x128.png"
|
||||
sips -z 256 256 "${ASSETS_DIR}/neovide-1024.png" --out "${ICONSET_DIR}/icon_128x128@2x.png"
|
||||
sips -z 256 256 "${ASSETS_DIR}/neovide-1024.png" --out "${ICONSET_DIR}/icon_256x256.png"
|
||||
sips -z 512 512 "${ASSETS_DIR}/neovide-1024.png" --out "${ICONSET_DIR}/icon_256x256@2x.png"
|
||||
sips -z 512 512 "${ASSETS_DIR}/neovide-1024.png" --out "${ICONSET_DIR}/icon_512x512.png"
|
||||
cp "${ASSETS_DIR}/neovide-1024.png" "${ICONSET_DIR}/icon_512x512@2x.png"
|
||||
|
||||
iconutil -c icns "${ICONSET_DIR}"
|
||||
rm -R "${ICONSET_DIR}"
|
||||
49
macos-builder/run
Executable file
49
macos-builder/run
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
TARGET="neovide"
|
||||
EXTRAS_DIR="extra"
|
||||
ASSETS_DIR="assets"
|
||||
RELEASE_DIR="target/release"
|
||||
BUNDLE_DIR="${RELEASE_DIR}/bundle"
|
||||
|
||||
APP_NAME="Neovide.app"
|
||||
APP_TEMPLATE="${EXTRAS_DIR}/osx/${APP_NAME}"
|
||||
APP_DIR="${BUNDLE_DIR}/osx"
|
||||
APP_BINARY="${RELEASE_DIR}/${TARGET}"
|
||||
APP_BINARY_DIR="${APP_DIR}/${APP_NAME}/Contents/MacOS"
|
||||
APP_EXTRAS_DIR="${APP_DIR}/${APP_NAME}/Contents/Resources"
|
||||
|
||||
DMG_NAME="Neovide.dmg"
|
||||
DMG_VOLNAME="Neovide"
|
||||
DMG_FILESYSTEM="HFS+"
|
||||
DMG_FORMAT="UDZO"
|
||||
DMG_ICNS="${APP_EXTRAS_DIR}/Neovide.icns"
|
||||
DMG_BACKGROUND="${ASSETS_DIR}/neovide-dmg-background.tiff"
|
||||
|
||||
# Make Neovide.app
|
||||
|
||||
mkdir -p "${APP_BINARY_DIR}"
|
||||
mkdir -p "${APP_EXTRAS_DIR}"
|
||||
cp -fRp "${APP_TEMPLATE}" "${APP_DIR}"
|
||||
cp -fp "${APP_BINARY}" "${APP_BINARY_DIR}"
|
||||
touch -r "${APP_BINARY}" "${APP_DIR}/${APP_NAME}"
|
||||
codesign --remove-signature "${APP_DIR}/${APP_NAME}"
|
||||
codesign --force --deep --sign - "${APP_DIR}/${APP_NAME}"
|
||||
echo "Created '${APP_NAME}' in '${APP_DIR}'"
|
||||
|
||||
# Make Neovide.dmg
|
||||
|
||||
create-dmg \
|
||||
--filesystem "${DMG_FILESYSTEM}" \
|
||||
--format "${DMG_FORMAT}" \
|
||||
--volname "${DMG_VOLNAME}" \
|
||||
--volicon "${DMG_ICNS}" \
|
||||
--background "${DMG_BACKGROUND}" \
|
||||
--window-size 650 470 \
|
||||
--icon-size 80 \
|
||||
--icon Neovide.app 240 320 \
|
||||
--app-drop-link 410 320 \
|
||||
"${APP_DIR}/${DMG_NAME}" \
|
||||
"${APP_DIR}/${APP_NAME}"
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
#[cfg(windows)]
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
use std::io::IsTerminal;
|
||||
use std::process::{Command as StdCommand, Stdio};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
|
@ -233,10 +232,6 @@ fn platform_which(bin: &str) -> Option<String> {
|
|||
None
|
||||
}
|
||||
|
||||
pub fn is_tty() -> bool {
|
||||
std::io::stdout().is_terminal()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn nvim_cmd_impl(bin: String, args: Vec<String>) -> TokioCommand {
|
||||
let (cmd, cmd_args) = build_login_cmd_args(
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ fn handle_command_arg_as_path_or_default(args: &mut Vec<String>) -> Option<Strin
|
|||
pub async fn setup_tty_startup_directory(
|
||||
nvim: &Neovim<NeovimWriter>,
|
||||
) -> Result<(), Box<CallError>> {
|
||||
use self::command::is_tty;
|
||||
use crate::utils::is_tty;
|
||||
|
||||
if is_tty() {
|
||||
return Ok(());
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ use crate::{
|
|||
settings::{SettingLocation, SETTINGS},
|
||||
};
|
||||
|
||||
use crate::bridge::{command::is_tty, setup_tty_startup_directory};
|
||||
use crate::bridge::setup_tty_startup_directory;
|
||||
use crate::utils::is_tty;
|
||||
|
||||
const INIT_LUA: &str = include_str!("../../lua/init.lua");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::{iter, mem};
|
||||
|
||||
use crate::utils::is_tty;
|
||||
use crate::{dimensions::Dimensions, frame::Frame, settings::*};
|
||||
|
||||
use anyhow::Result;
|
||||
|
|
@ -21,6 +22,10 @@ fn get_styles() -> Styles {
|
|||
.placeholder(styling::AnsiColor::Cyan.on_default())
|
||||
}
|
||||
|
||||
fn is_tty_str() -> &'static str {
|
||||
is_tty().then_some("1").unwrap_or("0")
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Parser)]
|
||||
#[command(version, about, long_about = None, styles = get_styles())]
|
||||
pub struct CmdLineSettings {
|
||||
|
|
@ -66,7 +71,7 @@ pub struct CmdLineSettings {
|
|||
pub title_hidden: bool,
|
||||
|
||||
/// Spawn a child process and leak it [DEFAULT]
|
||||
#[arg(long = "fork", env = "NEOVIDE_FORK", action = ArgAction::SetTrue, default_value = "1", value_parser = FalseyValueParser::new())]
|
||||
#[arg(long = "fork", env = "NEOVIDE_FORK", action = ArgAction::SetTrue, default_value = is_tty_str(), value_parser = FalseyValueParser::new())]
|
||||
pub fork: bool,
|
||||
|
||||
/// Be "blocking" and let the shell persist as parent process. Takes precedence over `--fork`.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
mod ring_buffer;
|
||||
|
||||
pub use ring_buffer::*;
|
||||
|
||||
pub fn is_tty() -> bool {
|
||||
use std::io::IsTerminal;
|
||||
std::io::stdout().is_terminal()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,13 @@ use icrate::{
|
|||
},
|
||||
Foundation::{MainThreadMarker, NSObject, NSPoint, NSProcessInfo, NSRect, NSSize, NSString},
|
||||
};
|
||||
use objc2::{declare_class, msg_send_id, mutability::InteriorMutable, rc::Id, sel, ClassType};
|
||||
use objc2::{
|
||||
declare_class, msg_send_id,
|
||||
mutability::InteriorMutable,
|
||||
rc::Id,
|
||||
runtime::{AnyClass, AnyObject},
|
||||
sel, ClassType,
|
||||
};
|
||||
|
||||
use csscolorparser::Color;
|
||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
||||
|
|
@ -409,3 +415,47 @@ impl Menu {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_file_handler() {
|
||||
use objc2::rc::autoreleasepool;
|
||||
|
||||
extern "C" fn handle_open_files(
|
||||
_this: &mut AnyObject,
|
||||
_sel: objc2::runtime::Sel,
|
||||
_sender: &objc2::runtime::AnyObject,
|
||||
files: &mut icrate::Foundation::NSArray<icrate::Foundation::NSString>,
|
||||
) {
|
||||
autoreleasepool(|pool| {
|
||||
for file in files.iter() {
|
||||
let path = file.as_str(pool).to_owned();
|
||||
send_ui(ParallelCommand::FileDrop(path));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unsafe {
|
||||
use objc2::declare::ClassBuilder;
|
||||
use objc2::msg_send;
|
||||
|
||||
let app = NSApplication::sharedApplication();
|
||||
let delegate = app.delegate().unwrap();
|
||||
|
||||
// Find out class of the NSApplicationDelegate
|
||||
let class: &AnyClass = msg_send![&delegate, class];
|
||||
|
||||
// register subclass of whatever was in delegate
|
||||
let mut my_class = ClassBuilder::new("NeovideApplicationDelegate", class).unwrap();
|
||||
my_class.add_method(
|
||||
sel!(application:openFiles:),
|
||||
handle_open_files as unsafe extern "C" fn(_, _, _, _) -> _,
|
||||
);
|
||||
let class = my_class.register();
|
||||
|
||||
// this should be safe as:
|
||||
// * our class is a subclass
|
||||
// * no new ivars
|
||||
// * overriden methods are compatible with old (we implement protocol method)
|
||||
let delegate_obj = Id::cast::<AnyObject>(delegate);
|
||||
AnyObject::set_class(&delegate_obj, class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,10 @@ pub fn create_event_loop() -> EventLoop<UserEvent> {
|
|||
let mut builder = EventLoopBuilder::<UserEvent>::with_user_event();
|
||||
#[cfg(target_os = "macos")]
|
||||
builder.with_default_menu(false);
|
||||
builder.build().expect("Failed to create winit event loop")
|
||||
let event_loop = builder.build().expect("Failed to create winit event loop");
|
||||
#[cfg(target_os = "macos")]
|
||||
crate::window::macos::register_file_handler();
|
||||
event_loop
|
||||
}
|
||||
|
||||
pub fn create_window(
|
||||
|
|
|
|||
Loading…
Reference in a new issue