Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.sh text eol=lf
*.ps1 text eol=crlf
*.bat text eol=crlf
53 changes: 51 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ A lightweight, fast and multi-functional desktop text editor for Windows, macOS
- [Features](#features)
- [Keyboard shortcuts](#keyboard-shortcuts)
- [Supported languages](#supported-languages)
- [Install from source](#install-from-source)
- [Getting started](#getting-started)
- [Building installers](#building-installers)
- [Development](#development)
Expand Down Expand Up @@ -140,11 +141,59 @@ Syntax highlighting is chosen from the file name or extension, and can be change

Plain text, JavaScript, TypeScript, JSON, XML, HTML, CSS, YAML, Markdown, Java, Kotlin, C/C++, C#, Go, Rust, Python, Ruby, PHP, SQL, PL/SQL, Shell, Batch, PowerShell, INI, Properties, TOML, Dockerfile and Makefile.

## Install from source

The `install/` folder has a script per operating system that builds Note Manager from this repository and installs it. Each script checks for Git and Node.js 22.17+ or 24+, runs `npm ci` and builds a clean `out/` folder, installs the result over any earlier installation and starts the app. Close Note Manager before running one.

| System | Script | What it installs |
|---|---|---|
| Windows | `install\install-windows.bat` (or `install\install-windows.ps1`) | Builds the Squirrel installer with `npm run make` and runs it, which installs the app for the current user |
| macOS | `install/install-macos.sh` | Builds the DMG and ZIP with `npm run make` and copies `Note Manager.app` into `/Applications` (or `~/Applications` when `/Applications` is not writable) |
| Linux | `install/install-linux.sh` | On Debian and Ubuntu, builds the DEB package with `npm run make` and installs it with `apt` (installing `fakeroot` first when it is missing). On other distributions, builds the app with `npm run package` and installs it for the current user in `~/.local/share/note-manager`, with `~/.local/bin/note-manager` and a desktop entry |

`install/linux_clean_install.sh` is kept for existing users and runs `install-linux.sh`.

From a clone, run the script for your system:

```bash
git clone https://github.com/Note-Manager/note-manager
cd note-manager
./install/install-linux.sh # or ./install/install-macos.sh
```

```bat
git clone https://github.com/Note-Manager/note-manager
cd note-manager
install\install-windows.bat
```

A script can also be downloaded on its own. It then clones the repository into `~/note-manager` (`%USERPROFILE%\note-manager` on Windows), or updates that clone when it already exists, and builds it:

```bash
curl -fsSL https://raw.githubusercontent.com/Note-Manager/note-manager/main/install/install-linux.sh | bash
curl -fsSL https://raw.githubusercontent.com/Note-Manager/note-manager/main/install/install-macos.sh | bash
```

```powershell
Invoke-WebRequest https://raw.githubusercontent.com/Note-Manager/note-manager/main/install/install-windows.ps1 -OutFile install-windows.ps1
powershell -ExecutionPolicy Bypass -File .\install-windows.ps1
```

Options:

| Shell scripts | PowerShell | Meaning |
|---|---|---|
| `--dir <folder>` | `-Dir <folder>` | Where to clone the repository when the script is not run from a clone (default `~/note-manager`) |
| `--ref <branch-or-tag>` | `-Ref <branch-or-tag>` | Branch or tag to build (default `main` for a clone the script made; a clone the script runs from keeps its current branch) |
| `--help` | `-Help` | Show the usage |

Options go after `bash -s --` when the script is piped, for example `curl -fsSL <script url> | bash -s -- --ref main`.

## Getting started

Prerequisites:

- [Node.js](https://nodejs.org/) 22.13 or newer (Node 22 LTS is recommended; CI uses Node 22)
- [Node.js](https://nodejs.org/) 22.17 or newer, or 24 and newer (Node 22 LTS is recommended; CI uses Node 22)
- npm 10 or newer
- Git

Expand All @@ -164,7 +213,7 @@ npm run package # packaged app in out/
npm run make # installers in out/make/
```

`npm run make` builds the installers for the current platform: a Squirrel installer on Windows, DMG and ZIP on macOS, and DEB/RPM packages on Linux. On Debian or Ubuntu, `linux_clean_install.sh` removes an existing installation, builds a new DEB package, installs it and starts the app.
`npm run make` builds the installers for the current platform: a Squirrel installer on Windows, DMG and ZIP on macOS, and a DEB package on Linux. To build and install in one step, use the scripts in [`install/`](#install-from-source).

Windows installers are also built by the "Build Windows Installer" workflow on every push to `main`, and a macOS build can be started manually from the "Build and Package Note Manager" workflow.

Expand Down
180 changes: 180 additions & 0 deletions install/install-linux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#!/usr/bin/env bash
set -euo pipefail

REPO_URL="https://github.com/Note-Manager/note-manager.git"
PACKAGE_NAME="note-manager"
PRODUCT_NAME="Note Manager"
LOCAL_APP_DIR="$HOME/.local/share/$PACKAGE_NAME"
LOCAL_BIN="$HOME/.local/bin/$PACKAGE_NAME"
DESKTOP_FILE="$HOME/.local/share/applications/$PACKAGE_NAME.desktop"

target_dir="$HOME/$PACKAGE_NAME"
ref=""

usage() {
cat <<EOF
Usage: install-linux.sh [--dir <folder>] [--ref <branch-or-tag>]

Builds $PRODUCT_NAME from source and installs it.
Run from a $PRODUCT_NAME checkout, it builds that checkout.
Otherwise it clones $REPO_URL into --dir (default: $target_dir).
--ref checks out a branch or tag before building (default for a clone: main).
On Debian and Ubuntu it builds and installs the DEB package with apt.
On other distributions it installs the packaged app for the current user.
EOF
}

fail() {
echo "Error: $*" >&2
exit 1
}

step() {
printf "\n==> %s\n" "$*"
}

parse_args() {
while [ $# -gt 0 ]; do
case "$1" in
--dir|--ref)
[ $# -ge 2 ] || fail "$1 needs a value"
if [ "$1" = "--dir" ]; then target_dir="$2"; else ref="$2"; fi
shift 2
;;
-h|--help) usage; exit 0 ;;
*) usage >&2; fail "Unknown option: $1" ;;
esac
done
}

require_command() {
command -v "$1" >/dev/null 2>&1 || fail "$1 is required. $2"
}

check_prerequisites() {
require_command git "Install Git from your package manager."
require_command node "Install Node.js 22.17+ or 24+ from https://nodejs.org/"
require_command npm "npm is installed together with Node.js."
node -e 'const [major, minor] = process.versions.node.split(".").map(Number); process.exit(major >= 24 || (major === 22 && minor >= 17) ? 0 : 1)' \
|| fail "Node.js $(node -v) is not supported. Use Node.js 22.17+ or 24+."
if pgrep -x "$PACKAGE_NAME" >/dev/null 2>&1; then
fail "$PRODUCT_NAME is running. Close it and run the script again."
fi
}

is_note_manager() {
[ -f "$1/package.json" ] && grep -q "\"name\": \"$PACKAGE_NAME\"" "$1/package.json"
}

script_checkout() {
local script="${BASH_SOURCE[0]:-}"
[ -f "$script" ] || return 1
local root
root="$(cd "$(dirname "$script")/.." && pwd)"
is_note_manager "$root" && echo "$root"
}

switch_ref() {
[ -d "$source_dir/.git" ] || fail "$source_dir is not a Git clone, so --ref cannot be used."
step "Checking out $1"
git -C "$source_dir" fetch --tags origin
git -C "$source_dir" checkout "$1"
if git -C "$source_dir" show-ref --verify --quiet "refs/remotes/origin/$1"; then
git -C "$source_dir" merge --ff-only "origin/$1"
fi
}

prepare_source() {
if source_dir="$(script_checkout)"; then
step "Using the checkout in $source_dir"
if [ -n "$ref" ]; then switch_ref "$ref"; fi
return
fi
source_dir="$target_dir"
if [ ! -e "$source_dir" ]; then
step "Cloning $REPO_URL into $source_dir"
git clone --branch "${ref:-main}" "$REPO_URL" "$source_dir"
return
fi
is_note_manager "$source_dir" || fail "$source_dir exists and is not a $PRODUCT_NAME checkout. Choose another folder with --dir."
switch_ref "${ref:-main}"
}

build() {
cd "$source_dir"
step "Installing dependencies"
rm -rf out
npm ci
step "Building ($1)"
npm run "$1"
}

ensure_deb_tools() {
command -v fakeroot >/dev/null 2>&1 && return
step "Installing fakeroot, which the DEB build needs"
sudo apt-get update
sudo apt-get install -y fakeroot
}

install_deb() {
local deb
deb="$(find "$source_dir/out/make/deb" -name "*.deb" | head -n 1)"
[ -n "$deb" ] || fail "No DEB package was built in out/make/deb."
step "Installing $(basename "$deb")"
if dpkg -s "$PACKAGE_NAME" >/dev/null 2>&1; then
sudo apt-get remove -y "$PACKAGE_NAME"
fi
sudo apt-get install -y "$deb"
}

install_for_user() {
local packaged
packaged="$(find "$source_dir/out" -maxdepth 1 -type d -name "$PRODUCT_NAME-linux-*" | head -n 1)"
[ -n "$packaged" ] || fail "No packaged app was built in out/."
step "Installing into $LOCAL_APP_DIR"
rm -rf "$LOCAL_APP_DIR"
mkdir -p "$(dirname "$LOCAL_APP_DIR")" "$(dirname "$LOCAL_BIN")" "$(dirname "$DESKTOP_FILE")"
cp -R "$packaged" "$LOCAL_APP_DIR"
ln -sf "$LOCAL_APP_DIR/$PACKAGE_NAME" "$LOCAL_BIN"
cat > "$DESKTOP_FILE" <<EOF
[Desktop Entry]
Type=Application
Name=$PRODUCT_NAME
Exec="$LOCAL_APP_DIR/$PACKAGE_NAME" %F
Icon=$LOCAL_APP_DIR/resources/Icons/$PACKAGE_NAME.png
Categories=Utility;TextEditor;
Terminal=false
EOF
case ":$PATH:" in
*":$(dirname "$LOCAL_BIN"):"*) ;;
*) echo "Add $(dirname "$LOCAL_BIN") to PATH to start $PRODUCT_NAME with '$PACKAGE_NAME'." ;;
esac
}

launch() {
if [ -z "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]; then
echo "$PRODUCT_NAME is installed. Start it from your desktop's app menu."
return
fi
step "Starting $PRODUCT_NAME"
nohup "$1" >/dev/null 2>&1 &
}

main() {
parse_args "$@"
check_prerequisites
prepare_source
if command -v apt-get >/dev/null 2>&1; then
ensure_deb_tools
build make
install_deb
launch "$PACKAGE_NAME"
else
build package
install_for_user
launch "$LOCAL_BIN"
fi
step "$PRODUCT_NAME $(node -p "require('./package.json').version") is installed"
}

main "$@"
Loading
Loading