mirror of
https://github.com/Matir/skel.git
synced 2026-06-10 11:13:40 -07:00
Add newnote
This commit is contained in:
208
bin/newnote
Executable file
208
bin/newnote
Executable file
@@ -0,0 +1,208 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Exit on error, undefined variables, and pipe failures
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
show_help() {
|
||||||
|
cat << EOF
|
||||||
|
Usage: $(basename "$0") [options] <note_name_or_path>
|
||||||
|
|
||||||
|
Create a new note in your Obsidian vault.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-v, --vault <dir> Specify the Obsidian vault directory.
|
||||||
|
--overwrite Overwrite the file if it already exists.
|
||||||
|
-h, --help Show this help message.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
VAULT_DIR=""
|
||||||
|
OVERWRITE="false"
|
||||||
|
NOTE_PATH=""
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-v|--vault)
|
||||||
|
if [[ -z "${2:-}" ]]; then
|
||||||
|
echo "Error: --vault requires a directory path." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
VAULT_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--overwrite)
|
||||||
|
OVERWRITE="true"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo "Error: Unknown option: $1" >&2
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ -n "$NOTE_PATH" ]]; then
|
||||||
|
echo "Error: Multiple note paths provided: $NOTE_PATH and $1" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
NOTE_PATH="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "$NOTE_PATH" ]]; then
|
||||||
|
echo "Error: Missing note path/name." >&2
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 1. Find the Obsidian vault.
|
||||||
|
if [[ -n "$VAULT_DIR" ]]; then
|
||||||
|
# -v/--vault was passed. Check that the directory exists and contains a .obsidian directory.
|
||||||
|
if [[ ! -d "$VAULT_DIR" ]]; then
|
||||||
|
echo "Error: Specified vault directory does not exist: $VAULT_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ ! -d "$VAULT_DIR/.obsidian" ]]; then
|
||||||
|
echo "Error: Specified directory is not an Obsidian vault (missing .obsidian): $VAULT_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
VAULT_DIR="$(cd "$VAULT_DIR" && pwd)"
|
||||||
|
else
|
||||||
|
# Search directories upward for a parent (or current) directory containing a .obsidian subdirectory.
|
||||||
|
# Stop at the user's home directory or a filesystem boundary.
|
||||||
|
CURRENT_DIR="$PWD"
|
||||||
|
FOUND_VAULT=""
|
||||||
|
|
||||||
|
get_device_id() {
|
||||||
|
local dir="$1"
|
||||||
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
stat -f '%d' "$dir" 2>/dev/null || echo ""
|
||||||
|
else
|
||||||
|
stat -c '%d' "$dir" 2>/dev/null || echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_DEV="$(get_device_id "$CURRENT_DIR")"
|
||||||
|
|
||||||
|
while [[ "$CURRENT_DIR" != "/" && "$CURRENT_DIR" != "$HOME" ]]; do
|
||||||
|
if [[ -d "$CURRENT_DIR/.obsidian" ]]; then
|
||||||
|
FOUND_VAULT="$CURRENT_DIR"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
PARENT_DIR="$(dirname "$CURRENT_DIR")"
|
||||||
|
if [[ "$PARENT_DIR" == "$CURRENT_DIR" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check filesystem boundary
|
||||||
|
PARENT_DEV="$(get_device_id "$PARENT_DIR")"
|
||||||
|
if [[ -n "$CURRENT_DEV" && -n "$PARENT_DEV" && "$CURRENT_DEV" != "$PARENT_DEV" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
CURRENT_DIR="$PARENT_DIR"
|
||||||
|
CURRENT_DEV="$PARENT_DEV"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check the last checked directory (could be HOME or /)
|
||||||
|
if [[ -z "$FOUND_VAULT" && -d "$CURRENT_DIR/.obsidian" ]]; then
|
||||||
|
FOUND_VAULT="$CURRENT_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$FOUND_VAULT" ]]; then
|
||||||
|
VAULT_DIR="$FOUND_VAULT"
|
||||||
|
else
|
||||||
|
# Fallback paths in order: ~/Notes, ~/Obsidian/Notes, ~/Personal/Notes, ~/Projects/Notes.
|
||||||
|
FALLBACKS=(
|
||||||
|
"$HOME/Notes"
|
||||||
|
"$HOME/Obsidian/Notes"
|
||||||
|
"$HOME/Personal/Notes"
|
||||||
|
"$HOME/Projects/Notes"
|
||||||
|
)
|
||||||
|
for path in "${FALLBACKS[@]}"; do
|
||||||
|
if [[ -d "$path" && -d "$path/.obsidian" ]]; then
|
||||||
|
VAULT_DIR="$(cd "$path" && pwd)"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$VAULT_DIR" ]]; then
|
||||||
|
echo "Error: Could not find an Obsidian vault. Please specify one with -v/--vault." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Strip leading slash from NOTE_PATH to handle relative paths properly
|
||||||
|
NOTE_PATH="${NOTE_PATH#/}"
|
||||||
|
|
||||||
|
# 2. Determine if current working directory is within the vault.
|
||||||
|
# Resolve physical paths to handle symlinks cleanly.
|
||||||
|
RESOLVED_PWD="$(pwd -P)"
|
||||||
|
RESOLVED_VAULT="$(cd "$VAULT_DIR" && pwd -P)"
|
||||||
|
|
||||||
|
if [[ "$RESOLVED_PWD" == "$RESOLVED_VAULT" || "$RESOLVED_PWD" == "$RESOLVED_VAULT"/* ]]; then
|
||||||
|
# Within the vault, treat relative to CWD
|
||||||
|
TARGET_FILE="$PWD/$NOTE_PATH"
|
||||||
|
else
|
||||||
|
# Not within the vault, treat relative to vault root
|
||||||
|
TARGET_FILE="$VAULT_DIR/$NOTE_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_DIR="$(dirname "$TARGET_FILE")"
|
||||||
|
TARGET_BASE="$(basename "$TARGET_FILE")"
|
||||||
|
|
||||||
|
# If there's no file extension on the argument, add .md.
|
||||||
|
if [[ "$TARGET_BASE" != *.* ]]; then
|
||||||
|
TARGET_BASE="$TARGET_BASE.md"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_FILE="$TARGET_DIR/$TARGET_BASE"
|
||||||
|
|
||||||
|
# If the necessary directory components don't exist, create them.
|
||||||
|
if [[ ! -d "$TARGET_DIR" ]]; then
|
||||||
|
mkdir -p "$TARGET_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. If the file exists and there's no --overwrite argument, throw an error.
|
||||||
|
if [[ -f "$TARGET_FILE" && "$OVERWRITE" != "true" ]]; then
|
||||||
|
echo "Error: File already exists: $TARGET_FILE (use --overwrite to replace it)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. If the path ends in .md (case-insensitive), generate appropriate YAML front matter and write it to the new file.
|
||||||
|
if [[ "${TARGET_BASE,,}" == *.md ]]; then
|
||||||
|
NOTE_TITLE="${TARGET_BASE%.*}"
|
||||||
|
CURRENT_DATE="$(date +"%Y-%m-%d %H:%M")"
|
||||||
|
|
||||||
|
cat << EOF > "$TARGET_FILE"
|
||||||
|
---
|
||||||
|
title: "$NOTE_TITLE"
|
||||||
|
date: $CURRENT_DATE
|
||||||
|
tags: []
|
||||||
|
---
|
||||||
|
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
# Just touch the file to ensure it exists
|
||||||
|
touch "$TARGET_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. Open the user's $EDITOR (falling back to vim/vi if unset) pointing to the new file.
|
||||||
|
EDITOR="${EDITOR:-}"
|
||||||
|
if [[ -z "$EDITOR" ]]; then
|
||||||
|
if command -v vim >/dev/null 2>&1; then
|
||||||
|
EDITOR="vim"
|
||||||
|
else
|
||||||
|
EDITOR="vi"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$EDITOR" "$TARGET_FILE"
|
||||||
Reference in New Issue
Block a user