Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c08d69c4d0 | ||
|
|
919418ec3e | ||
|
|
171b6a2e7d | ||
|
|
da021305d9 | ||
|
|
3fdd3ce868 | ||
|
|
4049c021a5 | ||
|
|
409ad657cc | ||
|
|
74c817473c | ||
|
|
0916fc3cf6 | ||
|
|
ce3fd6955b | ||
|
|
eb99682dbd | ||
|
|
6861be823f | ||
|
|
b8fbc2028f | ||
|
|
bf0647eef2 | ||
|
|
9a79d024b1 | ||
|
|
c80fff41d0 | ||
|
|
29b3024dc1 | ||
|
|
757d883424 |
No files matched your search
@@ -1,15 +1 @@
|
|||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: Felitendo
|
|
||||||
patreon: # Replace with a single Patreon username
|
|
||||||
open_collective: # Replace with a single Open Collective username
|
|
||||||
ko_fi: felitendo
|
ko_fi: felitendo
|
||||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
|
||||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
||||||
liberapay: # Replace with a single Liberapay username
|
|
||||||
issuehunt: # Replace with a single IssueHunt username
|
|
||||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
|
||||||
polar: # Replace with a single Polar username
|
|
||||||
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
|
|
||||||
thanks_dev: # Replace with a single thanks.dev username
|
|
||||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
name: 💡 Feature request
|
||||||
|
description: An idea to make bottles-opener better.
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checks
|
||||||
|
attributes:
|
||||||
|
label: Before you start
|
||||||
|
options:
|
||||||
|
- label: I searched the issues and this is not requested yet.
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: problem
|
||||||
|
attributes:
|
||||||
|
label: What problem would this solve?
|
||||||
|
description: What are you trying to do, and what gets in the way?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: idea
|
||||||
|
attributes:
|
||||||
|
label: What would you like?
|
||||||
|
description: How it could work. A rough idea is fine.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: alternatives
|
||||||
|
attributes:
|
||||||
|
label: Other ways you thought of
|
||||||
|
- type: textarea
|
||||||
|
id: more
|
||||||
|
attributes:
|
||||||
|
label: Anything else?
|
||||||
|
description: Mockups, screenshots, or other tools that do it well.
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
name: 🐛 Bug report
|
||||||
|
description: Something does not work as it should.
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: Thanks for taking the time! The more you fill in, the faster it can be fixed.
|
||||||
|
- type: checkboxes
|
||||||
|
id: checks
|
||||||
|
attributes:
|
||||||
|
label: Before you start
|
||||||
|
options:
|
||||||
|
- label: I searched the issues and this is not reported yet.
|
||||||
|
required: true
|
||||||
|
- label: I use the latest version.
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: what
|
||||||
|
attributes:
|
||||||
|
label: What happened?
|
||||||
|
description: What did you do, and what went wrong?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: steps
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
placeholder: |
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
- type: textarea
|
||||||
|
id: expected
|
||||||
|
attributes:
|
||||||
|
label: What did you expect?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: file
|
||||||
|
attributes:
|
||||||
|
label: File type and program
|
||||||
|
description: The file type, the program that should open it, and its bottle.
|
||||||
|
placeholder: .psd, Photoshop in the bottle "Adobe"
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: Version
|
||||||
|
description: The output of `bottles-opener --version`.
|
||||||
|
placeholder: bottles-opener 0.1.1
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: install
|
||||||
|
attributes:
|
||||||
|
label: How did you install it?
|
||||||
|
options:
|
||||||
|
- AUR
|
||||||
|
- Built from source
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: system
|
||||||
|
attributes:
|
||||||
|
label: System
|
||||||
|
description: Distribution, desktop, and your Bottles version and how it is installed.
|
||||||
|
placeholder: CachyOS, KDE Plasma 6.4, Bottles 51 (Flatpak)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Status and logs
|
||||||
|
description: The output of `bottles-opener status` and `bottles-opener list`.
|
||||||
|
render: shell
|
||||||
|
- type: textarea
|
||||||
|
id: more
|
||||||
|
attributes:
|
||||||
|
label: Anything else?
|
||||||
|
description: Screenshots, videos or anything else that could help.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
Executable
+136
@@ -0,0 +1,136 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Builds the GitHub release notes for a tag, the way big projects such as
|
||||||
|
# Immich lay them out: the hand-written entry from CHANGELOG.md (a welcome,
|
||||||
|
# the highlights), a support section, then every commit since the last
|
||||||
|
# release, sorted by kind, and a link to the full changelog.
|
||||||
|
#
|
||||||
|
# .github/release-notes.sh v1.2.0 the notes
|
||||||
|
# .github/release-notes.sh --title v1.2.0 the title (checks the entry exists)
|
||||||
|
#
|
||||||
|
# Commit authors come from the GitHub API through gh. Without it the list
|
||||||
|
# goes without them.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
||||||
|
|
||||||
|
title=0
|
||||||
|
if [[ ${1:-} == --title ]]; then
|
||||||
|
title=1
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
tag="${1:?usage: release-notes.sh [--title] vX.Y.Z}"
|
||||||
|
|
||||||
|
if ! grep -qx "## $tag" CHANGELOG.md; then
|
||||||
|
echo "CHANGELOG.md has no entry for $tag. Add \"## $tag\" first." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if (( title )); then
|
||||||
|
printf '%s\n' "$tag"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo="${GITHUB_REPOSITORY:-$(git remote get-url origin | sed -E 's#^.*github\.com[:/]##; s#\.git$##')}"
|
||||||
|
name="${repo#*/}"
|
||||||
|
|
||||||
|
# The entry: up to the next one, without the date line (GitHub shows the
|
||||||
|
# date), one heading level up, outside code blocks.
|
||||||
|
entry="$(awk -v h="## $tag" '
|
||||||
|
$0 == h { on = 1; next }
|
||||||
|
on && /^## / { exit }
|
||||||
|
!on { next }
|
||||||
|
/^```/ { code = !code }
|
||||||
|
!code && /^_[0-9]{4}-[0-9]{2}-[0-9]{2}_$/ { next }
|
||||||
|
!code && /^###/ { sub(/^#/, "") }
|
||||||
|
{ print }
|
||||||
|
' CHANGELOG.md | sed -e '/./,$!d')"
|
||||||
|
|
||||||
|
# The commits: from the last release, or from the start. A tag that does not
|
||||||
|
# exist yet is a preview of what HEAD would become.
|
||||||
|
if git rev-parse -q --verify "refs/tags/$tag" > /dev/null; then
|
||||||
|
target="$tag"
|
||||||
|
prev="$(git describe --tags --abbrev=0 --match 'v[0-9]*' "$tag^" 2>/dev/null || true)"
|
||||||
|
else
|
||||||
|
target="$(git rev-parse HEAD)"
|
||||||
|
prev="$(git describe --tags --abbrev=0 --match 'v[0-9]*' HEAD 2>/dev/null || true)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -A login=()
|
||||||
|
if command -v gh > /dev/null; then
|
||||||
|
if [[ -n $prev ]]; then
|
||||||
|
api=(api "repos/$repo/compare/$prev...$target" --jq '.commits[] | [.sha, (.author.login // "")] | @tsv')
|
||||||
|
else
|
||||||
|
api=(api --paginate "repos/$repo/commits?sha=$target&per_page=100" --jq '.[] | [.sha, (.author.login // "")] | @tsv')
|
||||||
|
fi
|
||||||
|
while IFS=$'\t' read -r sha who; do
|
||||||
|
[[ -n $who ]] && login[$sha]="$who"
|
||||||
|
done < <(gh "${api[@]}" 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -A list=()
|
||||||
|
count_maint=0
|
||||||
|
while IFS=$'\t' read -r sha subject body; do
|
||||||
|
# Version bumps say nothing a reader needs.
|
||||||
|
[[ $subject =~ ^(chore:\ )?($name\ )?v?[0-9]+\.[0-9]+\.[0-9]+$ ]] && continue
|
||||||
|
|
||||||
|
case "$subject" in
|
||||||
|
*!:*) kind=breaking ;;
|
||||||
|
feat:* | feat\(*) kind=feat ;;
|
||||||
|
fix:* | fix\(*) kind=fix ;;
|
||||||
|
perf:* | perf\(*) kind=enh ;;
|
||||||
|
docs:* | docs\(*) kind=docs ;;
|
||||||
|
chore* | ci:* | ci\(* | build* | refactor* | test* | style*) kind=maint ;;
|
||||||
|
# Older commits without a prefix, sorted by what they say.
|
||||||
|
*README* | *readme* | *Readme*) kind=docs ;;
|
||||||
|
Add\ * | Put\ * | Introduce\ *) kind=feat ;;
|
||||||
|
Fix\ * | Repair\ * | Recover\ * | Stop\ *) kind=fix ;;
|
||||||
|
*\ *) kind=enh ;;
|
||||||
|
*) kind=maint ;;
|
||||||
|
esac
|
||||||
|
[[ $body == *"BREAKING CHANGE"* ]] && kind=breaking
|
||||||
|
[[ $subject == "Initial commit" ]] && kind=maint
|
||||||
|
|
||||||
|
line="* $subject"
|
||||||
|
[[ -n ${login[$sha]:-} ]] && line+=" by @${login[$sha]}"
|
||||||
|
line+=" in https://github.com/$repo/commit/$sha"
|
||||||
|
list[$kind]+="$line"$'\n'
|
||||||
|
[[ $kind == maint ]] && count_maint=$((count_maint + 1))
|
||||||
|
done < <(git log --reverse --no-merges --format='%H%x09%s%x09%b%x1e' "${prev:+$prev..}$target" | tr '\n\036' ' \n' | sed 's/^ //')
|
||||||
|
|
||||||
|
changes=''
|
||||||
|
for pair in "breaking:🚨 Breaking Changes" "feat:🚀 Features" "enh:🌟 Enhancements" "fix:🐛 Bug fixes" "docs:📚 Documentation"; do
|
||||||
|
kind="${pair%%:*}"
|
||||||
|
[[ -n ${list[$kind]:-} ]] || continue
|
||||||
|
changes+="### ${pair#*:}"$'\n'"${list[$kind]}"
|
||||||
|
done
|
||||||
|
if [[ -n ${list[maint]:-} ]]; then
|
||||||
|
changes+=$'\n'"<details><summary>🧰 Maintenance ($count_maint)</summary>"$'\n\n'"${list[maint]}"$'\n'"</details>"$'\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n $prev ]]; then
|
||||||
|
full="**Full Changelog**: https://github.com/$repo/compare/$prev...$tag"
|
||||||
|
else
|
||||||
|
full="**Full Changelog**: https://github.com/$repo/commits/$tag"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A release with highlights is a big one: it gets a heading and the support
|
||||||
|
# section, as in Immich. A patch is a sentence or two and the list.
|
||||||
|
if grep -q '^## Highlights$' <<< "$entry"; then
|
||||||
|
cat <<EOF
|
||||||
|
# 🚀 $name $tag
|
||||||
|
|
||||||
|
$entry
|
||||||
|
|
||||||
|
## ☕ Support $name
|
||||||
|
|
||||||
|
If $name is useful to you, you can buy me a coffee. It keeps these tools going. Found a bug or have an idea? Tell me in the [issues](https://github.com/$repo/issues).
|
||||||
|
|
||||||
|
<a href="https://ko-fi.com/felitendo"><img src="https://storage.ko-fi.com/cdn/kofi5.png?v=6" alt="Buy me a coffee on Ko-fi" height="48"></a>
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
printf '%s\n\n' "$entry"
|
||||||
|
fi
|
||||||
|
printf "## What's Changed\n%s\n\n%s\n" "$changes" "$full"
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
What each release brings, newest first. The [GitHub releases](https://github.com/LoonixTools/bottles-opener/releases) add every commit that went into it.
|
||||||
|
|
||||||
|
## v0.1.1
|
||||||
|
|
||||||
|
_2026-09-24_
|
||||||
|
|
||||||
|
A small patch. The file types in the menu now stay on one line, however wide your terminal is.
|
||||||
|
|
||||||
|
## v0.1.0
|
||||||
|
|
||||||
|
_2026-09-21_
|
||||||
|
|
||||||
|
Welcome to the very first release of bottles-opener! You install FL Studio in Bottles, double-click your `.flp`, and it just opens. Like on Windows.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="620" alt="The bottles-opener menu in Konsole" src="https://raw.githubusercontent.com/LoonixTools/bottles-opener/91463a2a5062a779bb69ea5fc708967255f41c82/res/screenshots/menu.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- Your files open in their Windows program
|
||||||
|
- The right icons
|
||||||
|
- Add your own file types
|
||||||
@@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
## Style
|
## Style
|
||||||
|
|
||||||
Keep everything short — replies, explanations, comments, docs.
|
- Keep everything short: replies, explanations, comments, docs.
|
||||||
|
- Use simple English: short sentences, common words.
|
||||||
|
- Avoid em dashes (—). Do not just swap them for "-" either. Rewrite the sentence instead, for
|
||||||
|
example with a comma, a colon, brackets or two sentences.
|
||||||
|
|
||||||
## Commits
|
## Commits
|
||||||
|
|
||||||
@@ -11,6 +14,69 @@ Keep everything short — replies, explanations, comments, docs.
|
|||||||
- Subject as short as possible. Imperative, lowercase, no trailing period.
|
- Subject as short as possible. Imperative, lowercase, no trailing period.
|
||||||
- Body only when something genuinely cannot be inferred from the diff.
|
- Body only when something genuinely cannot be inferred from the diff.
|
||||||
- Never add `Co-Authored-By`, "Generated with" or any other AI attribution to commits or PR descriptions.
|
- Never add `Co-Authored-By`, "Generated with" or any other AI attribution to commits or PR descriptions.
|
||||||
|
- Do not commit or push before I have checked the changes locally and said they are fine. Then
|
||||||
|
commit and push. Several attempts at the same thing make one commit, and attempts that did not
|
||||||
|
work make none. Different things done in one session get a commit each. This also goes for
|
||||||
|
releases and tags.
|
||||||
|
|
||||||
|
## Releases
|
||||||
|
|
||||||
|
Releases look like the ones of big projects such as Immich. `.github/release-notes.sh <tag>` builds
|
||||||
|
the notes: the entry from `CHANGELOG.md` (welcome and highlights), a support section, every commit
|
||||||
|
since the last release sorted by its prefix (`feat`, `fix`, `docs`, ...) with author and link, and
|
||||||
|
the full changelog link. So commit subjects end up in public: keep them clear.
|
||||||
|
|
||||||
|
1. Read `git log <last tag>..HEAD` and pick the version: only fixes → patch, something new → minor,
|
||||||
|
something that breaks or needs the user to act → major.
|
||||||
|
2. Bump the version and add the entry at the top of `CHANGELOG.md`, in one commit (`chore: 1.4.0`).
|
||||||
|
3. Push, tag and create the release:
|
||||||
|
```bash
|
||||||
|
git tag v1.4.0 && git push origin main v1.4.0
|
||||||
|
gh release create v1.4.0 --title v1.4.0 --notes "$(.github/release-notes.sh v1.4.0)"
|
||||||
|
```
|
||||||
|
4. PKGBUILDS picks up the new release for the AUR on its own.
|
||||||
|
|
||||||
|
A minor or major release (has `### Highlights`, gets a heading and the support section):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## v1.4.0
|
||||||
|
|
||||||
|
_2026-09-24_
|
||||||
|
|
||||||
|
Welcome to bottles-opener `v1.4.0`! One or two sentences on what this release is about.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="480" alt="What the picture shows" src="https://raw.githubusercontent.com/LoonixTools/bottles-opener/v1.4.0/<path>">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
### 🚨 Breaking changes
|
||||||
|
|
||||||
|
- Only if there are any: what changed, and what the user has to do.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- First highlight, a few words
|
||||||
|
- Second highlight
|
||||||
|
```
|
||||||
|
|
||||||
|
A picture under the welcome is optional. To show the menu or another screen of the program, use a
|
||||||
|
real screenshot of it running in Konsole, in English. Never a text copy of the screen. The same goes
|
||||||
|
for the README. The highlights stay a plain list: no heading or text per highlight, the list of
|
||||||
|
commits explains the rest.
|
||||||
|
|
||||||
|
A patch release is just a sentence or two, for example: "A small patch. The menu no longer closes
|
||||||
|
when you press Enter." The list of commits follows on its own.
|
||||||
|
|
||||||
|
- Write for users: what they notice, not how the code does it. Friendly and simple.
|
||||||
|
- Commands and settings they type go in backticks, buttons and labels in bold.
|
||||||
|
- To change an old release: edit its entry, commit, then
|
||||||
|
`gh release edit <tag> --title <tag> --notes "$(.github/release-notes.sh <tag>)"`.
|
||||||
|
|
||||||
|
## README
|
||||||
|
|
||||||
|
- New UI (a window, a screen, a menu, a setting, a notification) gets a screenshot in the README,
|
||||||
|
next to the text about it. Like for releases: a real screenshot of it running, in English.
|
||||||
|
- When a screen changes, take its screenshot again. The README never shows an old one.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# bottles-opener - build and install
|
# bottles-opener: build and install
|
||||||
#
|
#
|
||||||
# Everything here is plain shell and one small Python script; "building" only
|
# Everything here is plain shell and one small Python script; "building" only
|
||||||
# means compiling the gettext catalogs and rendering the man page. Both targets
|
# means compiling the gettext catalogs and rendering the man page. Both targets
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
# Overridable so a packager can pass the version it is actually building
|
# Overridable so a packager can pass the version it is actually building
|
||||||
# (`make VERSION=$pkgver`). The literal below is the fallback for builds
|
# (`make VERSION=$pkgver`). The literal below is the fallback for builds
|
||||||
# straight from a checkout, and is what a release tag has to carry.
|
# straight from a checkout, and is what a release tag has to carry.
|
||||||
VERSION ?= 0.1.0
|
VERSION ?= 0.1.1
|
||||||
|
|
||||||
PREFIX ?= /usr
|
PREFIX ?= /usr
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
@@ -56,14 +56,14 @@ po/%.mo: po/%.po
|
|||||||
ifdef MSGFMT
|
ifdef MSGFMT
|
||||||
$(MSGFMT) --check --output-file=$@ $<
|
$(MSGFMT) --check --output-file=$@ $<
|
||||||
else
|
else
|
||||||
@echo "msgfmt not found - skipping $@"
|
@echo "msgfmt not found, skipping $@"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(MANPAGE): doc/bottles-opener.1.scd
|
$(MANPAGE): doc/bottles-opener.1.scd
|
||||||
ifdef SCDOC
|
ifdef SCDOC
|
||||||
$(SCDOC) < $< > $@
|
$(SCDOC) < $< > $@
|
||||||
else
|
else
|
||||||
@echo "scdoc not found - skipping $@"
|
@echo "scdoc not found, skipping $@"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Regenerates the template from the sources. The setting labels live in an
|
# Regenerates the template from the sources. The setting labels live in an
|
||||||
@@ -72,7 +72,7 @@ endif
|
|||||||
pot:
|
pot:
|
||||||
xgettext --language=Shell --from-code=UTF-8 -k --keyword=bo_msg --keyword=bo_msg_into \
|
xgettext --language=Shell --from-code=UTF-8 -k --keyword=bo_msg --keyword=bo_msg_into \
|
||||||
--package-name=bottles-opener --package-version=$(VERSION) \
|
--package-name=bottles-opener --package-version=$(VERSION) \
|
||||||
--msgid-bugs-address=https://github.com/Felitendo/bottles-opener/issues \
|
--msgid-bugs-address=https://github.com/LoonixTools/bottles-opener/issues \
|
||||||
--add-comments=TRANSLATORS --no-location --sort-output \
|
--add-comments=TRANSLATORS --no-location --sort-output \
|
||||||
--output=po/bottles-opener.pot.tmp src/bottles-opener $(LIBS)
|
--output=po/bottles-opener.pot.tmp src/bottles-opener $(LIBS)
|
||||||
msgcat --use-first --sort-output --output-file=po/bottles-opener.pot \
|
msgcat --use-first --sort-output --output-file=po/bottles-opener.pot \
|
||||||
@@ -92,7 +92,7 @@ check:
|
|||||||
shellcheck -x -e SC1090,SC1091 src/bottles-opener $(LIBS); \
|
shellcheck -x -e SC1090,SC1091 src/bottles-opener $(LIBS); \
|
||||||
echo "ok shellcheck"; \
|
echo "ok shellcheck"; \
|
||||||
else \
|
else \
|
||||||
echo "shellcheck not found - skipped"; \
|
echo "shellcheck not found, skipped"; \
|
||||||
fi
|
fi
|
||||||
@if command -v msgfmt >/dev/null 2>&1; then \
|
@if command -v msgfmt >/dev/null 2>&1; then \
|
||||||
for l in $(LINGUAS); do msgfmt --check --output-file=/dev/null po/$$l.po && echo "ok po/$$l.po"; done; \
|
for l in $(LINGUAS); do msgfmt --check --output-file=/dev/null po/$$l.po && echo "ok po/$$l.po"; done; \
|
||||||
|
|||||||
@@ -1,58 +1,97 @@
|
|||||||
# bottles-opener
|
<p align="center">
|
||||||
|
<img width="200" src="res/bottles-opener.svg" alt="bottles-opener">
|
||||||
|
</p>
|
||||||
|
|
||||||
bottles-opener is a CLI for linux that lets you double-click a file and have it open in its Windows program, inside its bottle.
|
<h1 align="center">bottles-opener</h1>
|
||||||
Works with FL Studio, Microsoft Office, Photoshop, Ableton and anything else you run through [Bottles](https://usebottles.com).
|
|
||||||
|
|
||||||
You install FL Studio in Bottles, double-click your `.flp` and... your file manager asks what an `.flp` is. This tool reads which files your Windows programs registered in their bottle - the same list Windows uses - teaches your system those types, gives them the program's icons and hands the file over the way Explorer would. One command and your files _✨just open✨_ (like on windows).
|
<h3 align="center">Double-click a file and it opens in its Windows program.</h3>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
FL Studio, Office, Photoshop, Ableton and anything else you run in <a href="https://usebottles.com">Bottles</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h5 align="center">
|
||||||
|
<a href="#install">Install</a> |
|
||||||
|
<a href="#how-to-use">How to use</a> |
|
||||||
|
<a href="https://github.com/LoonixTools/bottles-opener/issues">Report a bug</a>
|
||||||
|
</h5>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://ko-fi.com/felitendo"><img src="https://storage.ko-fi.com/cdn/kofi5.png?v=6" alt="Buy me a coffee on Ko-fi" height="48"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yay -S bottles-opener
|
||||||
|
```
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
Just run `bottles-opener`:
|
|
||||||
|
|
||||||
```
|
|
||||||
Bottles Opener
|
|
||||||
|
|
||||||
File opening ON
|
|
||||||
|
|
||||||
Bottles package
|
|
||||||
Programs found 5 in 2 bottles
|
|
||||||
File types .doc .docx .flp .fsc .fst .pptx .xlsx +31
|
|
||||||
New programs ON
|
|
||||||
Last applied 2 minutes ago
|
|
||||||
|
|
||||||
Double-click one of these files and it opens in its program.
|
|
||||||
|
|
||||||
[1] Turn file opening on or off
|
|
||||||
[2] Re-apply everything
|
|
||||||
[3] File types
|
|
||||||
[4] Programs
|
|
||||||
[5] Settings
|
|
||||||
[q] Quit
|
|
||||||
|
|
||||||
>
|
|
||||||
```
|
|
||||||
|
|
||||||
Press `[1]` and you're done. `[3]` lists every file type and lets you pick what opens it:
|
|
||||||
|
|
||||||
```
|
|
||||||
File types
|
|
||||||
|
|
||||||
▸ .docx Word · Office double-click
|
|
||||||
.flp FL Studio · FL Studio double-click
|
|
||||||
.psd Photoshop · Adobe Open With
|
|
||||||
```
|
|
||||||
|
|
||||||
`double-click` opens it. `Open With` only lists it in the right-click menu - that's what types get that already have an app on your system (`.docx` with LibreOffice), so nothing you picked gets taken away. Space switches.
|
|
||||||
|
|
||||||
`[4]` lists your programs; Enter edits their file types, so you can add any extension you like. Or without the menu:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bottles-opener add flp,fst "FL Studio"
|
bottles-opener
|
||||||
```
|
```
|
||||||
|
|
||||||
## How to install
|
<p align="center">
|
||||||
|
<img src="res/screenshots/menu.png" alt="The bottles-opener menu in Konsole: file opening on, 5 programs in 3 bottles" width="620">
|
||||||
|
</p>
|
||||||
|
|
||||||
**From source (for now)**
|
Press **1**. Your files _✨just open✨_ in their program, like on Windows.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>File types</summary>
|
||||||
|
|
||||||
|
**3** lists every file type. Space switches between:
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| double-click | Opens it in the program |
|
||||||
|
| Open With | Only listed in the right-click menu (when another app already opens it) |
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="res/screenshots/file-types.png" alt="The file types list in Konsole: .flp opens in FL Studio on a double-click, Office types are under Open With" width="620">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Your own file types: `bottles-opener add flp,fst "FL Studio"`
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## More
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>How it works</summary>
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| File types | Read from the bottle's registry, like Windows does. Known programs without entries come from a built-in list. |
|
||||||
|
| Icons | The ones Windows shows, taken from the program. |
|
||||||
|
| Opening | With the Windows path and the program's own switches, through `bottles-cli`. |
|
||||||
|
| Undo | `bottles-opener disable` puts back exactly what was there. |
|
||||||
|
|
||||||
|
Bottles 67 has file associations too, but it refuses extensions your system does not know (like
|
||||||
|
`.flp`), passes Linux paths and leaves the icons alone.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Commands</summary>
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| `bottles-opener` | The menu |
|
||||||
|
| `… enable` | Turn on |
|
||||||
|
| `… disable` | Undo everything |
|
||||||
|
| `… apply` | Pick up new programs |
|
||||||
|
| `… status` | What is set up |
|
||||||
|
| `… list` | All file types and what opens them |
|
||||||
|
| `… programs` | All programs and their file types |
|
||||||
|
| `… add <ext,...> <program> [bottle]` | Open file types with a program |
|
||||||
|
| `… remove <ext,...> [program]` | Stop opening file types |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Build from source</summary>
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make
|
make
|
||||||
@@ -60,48 +99,8 @@ sudo make install
|
|||||||
bottles-opener enable
|
bottles-opener enable
|
||||||
```
|
```
|
||||||
|
|
||||||
No root? `make install PREFIX=~/.local` works too.
|
`make install PREFIX=~/.local` works without root.
|
||||||
|
|
||||||
Needs `bash`, `python3` with PyYAML and icoextract (Bottles needs both itself) and `update-mime-database`.
|
</details>
|
||||||
|
|
||||||
## How it works
|
|
||||||
|
|
||||||
- **Which files:** read from the bottle's registry, like Windows does (`.flp` → `FL64.flp.26` → `FL64.exe "%1"`). Programs that registered nothing are matched against a built-in list: all of Office, FL Studio, Ableton, Cubase, Photoshop, Illustrator, Affinity, AutoCAD, SketchUp and more.
|
|
||||||
- **Unknown extensions** (`.flp`, `.msg`, `.als`, ...) get a MIME type in `~/.local/share/mime/packages/bottles-opener.xml`, named like in Windows ("FL Studio project file"). Where Linux means something else by an extension (`.mpp` is Musepack, `.fst` a tracker module) the file's signature tells them apart.
|
|
||||||
- **Icons:** the file gets the icon Windows shows, pulled out of the program. A type your system already knows keeps its icon until the program is its default.
|
|
||||||
- **Opening:** the path becomes the Windows path (`Z:\home\you\song.flp`), with the switches from the registry (Outlook `/f`, PowerPoint shows `/s`), started through `bottles-cli` with all your bottle's settings.
|
|
||||||
- **Flatpak Bottles:** the file goes through the document portal first, like `flatpak run --file-forwarding`.
|
|
||||||
|
|
||||||
Everything written is recorded, so `bottles-opener disable` puts back exactly what was there. New programs are picked up by a systemd path unit; `bottles-opener apply` does the same by hand.
|
|
||||||
|
|
||||||
## Why not just Bottles?
|
|
||||||
|
|
||||||
Bottles 67 has "File Associations" per program, but it rejects extensions your system doesn't know (so `.flp`, `.msg`, `.als` are "invalid"), passes Linux paths, doesn't know which program opens what and doesn't touch icons.
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
| Command | |
|
|
||||||
|---|---|
|
|
||||||
| `bottles-opener` | Interactive menu |
|
|
||||||
| `… enable` | Turn on, apply, start watching |
|
|
||||||
| `… disable` | Undo everything |
|
|
||||||
| `… apply` | Pick up new programs |
|
|
||||||
| `… apply --rebuild` | Redo from scratch |
|
|
||||||
| `… status` | What's set up |
|
|
||||||
| `… list` | All file types and what opens them |
|
|
||||||
| `… programs` | All programs and their file types |
|
|
||||||
| `… add <ext,...> <program> [bottle]` | Open file types with a program |
|
|
||||||
| `… remove <ext,...> [program]` | Stop opening file types |
|
|
||||||
|
|
||||||
## Building from source
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
```
|
|
||||||
|
|
||||||
Optionally needs `msgfmt` (gettext) and `scdoc`. Supports `PREFIX` and `DESTDIR`. `make check` runs syntax checks and shellcheck.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
GPL-3.0-or-later.
|
GPL-3.0-or-later.
|
||||||
@@ -125,4 +125,4 @@ dependencies), *update-mime-database*. Optional: *notify-send*.
|
|||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
||||||
Felitendo. https://github.com/Felitendo/bottles-opener
|
Felitendo. https://github.com/LoonixTools/bottles-opener
|
||||||
+16
-17
@@ -7,8 +7,8 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: bottles-opener 0.1.0\n"
|
"Project-Id-Version: bottles-opener 0.1.0\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/Felitendo/bottles-opener/issues\n"
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/bottles-opener/issues\n"
|
||||||
"POT-Creation-Date: 2026-09-21 11:30+0200\n"
|
"POT-Creation-Date: 2026-09-21 13:54+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -55,12 +55,12 @@ msgid "Already up to date for %s."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bottles could not be read - is python3 with PyYAML installed? Nothing was "
|
"Bottles could not be read. Is python3 with PyYAML installed? Nothing was "
|
||||||
"changed."
|
"changed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bottles is not installed - neither the package nor the Flatpak was found."
|
"Bottles is not installed. Neither the package nor the Flatpak was found."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Commands:"
|
msgid "Commands:"
|
||||||
@@ -82,10 +82,10 @@ msgstr ""
|
|||||||
msgid "File opening"
|
msgid "File opening"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "File opening is off - this is what it would do."
|
msgid "File opening is off and everything that was changed has been put back."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "File opening is off and everything that was changed has been put back."
|
msgid "File opening is off. This is what it would do."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "File opening is off. Turn it on first."
|
msgid "File opening is off. Turn it on first."
|
||||||
@@ -121,7 +121,7 @@ msgid "Looking at the bottles..."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, sh-printf-format
|
#, sh-printf-format
|
||||||
msgid "More than one program is called \"%s\" - name the bottle as well."
|
msgid "More than one program is called \"%s\". Name the bottle as well."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "New programs"
|
msgid "New programs"
|
||||||
@@ -152,12 +152,12 @@ msgid "No programs found in any bottle."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"No systemd user session - newly installed programs will not be picked up on "
|
"No systemd user session, so newly installed programs will not be picked up "
|
||||||
"their own."
|
"on their own."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, sh-printf-format
|
#, sh-printf-format
|
||||||
msgid "Not overwriting %s - it was not written by this program."
|
msgid "Not overwriting %s: this program did not write it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, sh-printf-format
|
#, sh-printf-format
|
||||||
@@ -246,17 +246,16 @@ msgstr ""
|
|||||||
msgid "Unknown command: %s"
|
msgid "Unknown command: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Up/Down select - Enter edits its file types - q goes back"
|
msgid "Up/Down: select, Enter: edit file types, q: back"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Up/Down select - Enter picks - q cancels"
|
msgid "Up/Down: select, Enter: pick, q: cancel"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Up/Down select - Space changes - q goes back"
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid "Up/Down: select, Space: switch, a: add, Del: remove, q: back"
|
||||||
"Up/Down select - Space switches - a adds one - Del removes - q goes back"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Usage: bottles-opener [command]"
|
msgid "Usage: bottles-opener [command]"
|
||||||
@@ -286,7 +285,7 @@ msgstr ""
|
|||||||
msgid "added"
|
msgid "added"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "could not be read - is python3 with PyYAML installed?"
|
msgid "could not be read (is python3 with PyYAML installed?)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "double-click"
|
msgid "double-click"
|
||||||
@@ -298,7 +297,7 @@ msgstr ""
|
|||||||
msgid "never"
|
msgid "never"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "none yet - add one under File types"
|
msgid "none yet, add one under File types"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "not found"
|
msgid "not found"
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: bottles-opener 0.1.0\n"
|
"Project-Id-Version: bottles-opener 0.1.0\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/Felitendo/bottles-opener/issues\n"
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/bottles-opener/issues\n"
|
||||||
"POT-Creation-Date: 2026-09-21 11:30+0200\n"
|
"POT-Creation-Date: 2026-09-21 13:54+0200\n"
|
||||||
"PO-Revision-Date: 2026-09-21 00:00+0200\n"
|
"PO-Revision-Date: 2026-09-21 00:00+0200\n"
|
||||||
"Last-Translator: Felitendo\n"
|
"Last-Translator: Felitendo\n"
|
||||||
"Language-Team: German\n"
|
"Language-Team: German\n"
|
||||||
@@ -55,16 +55,16 @@ msgid "Already up to date for %s."
|
|||||||
msgstr "Für %s ist schon alles eingerichtet."
|
msgstr "Für %s ist schon alles eingerichtet."
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bottles could not be read - is python3 with PyYAML installed? Nothing was "
|
"Bottles could not be read. Is python3 with PyYAML installed? Nothing was "
|
||||||
"changed."
|
"changed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Bottles konnte nicht gelesen werden - ist python3 mit PyYAML installiert? Es "
|
"Bottles konnte nicht gelesen werden. Ist python3 mit PyYAML installiert? Es "
|
||||||
"wurde nichts geändert."
|
"wurde nichts geändert."
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bottles is not installed - neither the package nor the Flatpak was found."
|
"Bottles is not installed. Neither the package nor the Flatpak was found."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Bottles ist nicht installiert - weder das Paket noch das Flatpak wurde "
|
"Bottles ist nicht installiert. Weder das Paket noch das Flatpak wurde "
|
||||||
"gefunden."
|
"gefunden."
|
||||||
|
|
||||||
msgid "Commands:"
|
msgid "Commands:"
|
||||||
@@ -87,13 +87,13 @@ msgstr "Ein Doppelklick auf eine dieser Dateien öffnet sie in ihrem Programm."
|
|||||||
msgid "File opening"
|
msgid "File opening"
|
||||||
msgstr "Dateien öffnen"
|
msgstr "Dateien öffnen"
|
||||||
|
|
||||||
msgid "File opening is off - this is what it would do."
|
|
||||||
msgstr "Dateien öffnen ist aus - so würde es aussehen."
|
|
||||||
|
|
||||||
msgid "File opening is off and everything that was changed has been put back."
|
msgid "File opening is off and everything that was changed has been put back."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Dateien öffnen ist aus und alles, was geändert wurde, ist wiederhergestellt."
|
"Dateien öffnen ist aus und alles, was geändert wurde, ist wiederhergestellt."
|
||||||
|
|
||||||
|
msgid "File opening is off. This is what it would do."
|
||||||
|
msgstr "Dateien öffnen ist aus. So würde es aussehen."
|
||||||
|
|
||||||
msgid "File opening is off. Turn it on first."
|
msgid "File opening is off. Turn it on first."
|
||||||
msgstr "Dateien öffnen ist aus. Schalte es zuerst ein."
|
msgstr "Dateien öffnen ist aus. Schalte es zuerst ein."
|
||||||
|
|
||||||
@@ -127,8 +127,8 @@ msgid "Looking at the bottles..."
|
|||||||
msgstr "Bottles werden durchsucht..."
|
msgstr "Bottles werden durchsucht..."
|
||||||
|
|
||||||
#, sh-printf-format
|
#, sh-printf-format
|
||||||
msgid "More than one program is called \"%s\" - name the bottle as well."
|
msgid "More than one program is called \"%s\". Name the bottle as well."
|
||||||
msgstr "Mehrere Programme heißen „%s“ - gib auch die Bottle an."
|
msgstr "Mehrere Programme heißen „%s“. Gib auch die Bottle an."
|
||||||
|
|
||||||
msgid "New programs"
|
msgid "New programs"
|
||||||
msgstr "Neue Programme"
|
msgstr "Neue Programme"
|
||||||
@@ -162,16 +162,16 @@ msgid "No programs found in any bottle."
|
|||||||
msgstr "In keiner Bottle wurden Programme gefunden."
|
msgstr "In keiner Bottle wurden Programme gefunden."
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"No systemd user session - newly installed programs will not be picked up on "
|
"No systemd user session, so newly installed programs will not be picked up "
|
||||||
"their own."
|
"on their own."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Keine systemd-Benutzersitzung - neu installierte Programme werden nicht von "
|
"Keine systemd-Benutzersitzung, daher werden neu installierte Programme nicht "
|
||||||
"selbst erkannt."
|
"von selbst erkannt."
|
||||||
|
|
||||||
#, sh-printf-format
|
#, sh-printf-format
|
||||||
msgid "Not overwriting %s - it was not written by this program."
|
msgid "Not overwriting %s: this program did not write it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"%s wird nicht überschrieben - die Datei stammt nicht von diesem Programm."
|
"%s wird nicht überschrieben, weil die Datei nicht von diesem Programm stammt."
|
||||||
|
|
||||||
#, sh-printf-format
|
#, sh-printf-format
|
||||||
msgid "Nothing opens .%s."
|
msgid "Nothing opens .%s."
|
||||||
@@ -261,20 +261,19 @@ msgstr "Ausschalten und alles wiederherstellen"
|
|||||||
msgid "Unknown command: %s"
|
msgid "Unknown command: %s"
|
||||||
msgstr "Unbekannter Befehl: %s"
|
msgstr "Unbekannter Befehl: %s"
|
||||||
|
|
||||||
msgid "Up/Down select - Enter edits its file types - q goes back"
|
msgid "Up/Down: select, Enter: edit file types, q: back"
|
||||||
msgstr "Hoch/Runter wählt - Enter bearbeitet die Dateitypen - q geht zurück"
|
msgstr "Hoch/Runter: wählen, Enter: Dateitypen bearbeiten, q: zurück"
|
||||||
|
|
||||||
msgid "Up/Down select - Enter picks - q cancels"
|
msgid "Up/Down: select, Enter: pick, q: cancel"
|
||||||
msgstr "Hoch/Runter wählt - Enter übernimmt - q bricht ab"
|
msgstr "Hoch/Runter: wählen, Enter: übernehmen, q: abbrechen"
|
||||||
|
|
||||||
msgid "Up/Down select - Space changes - q goes back"
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
msgstr "Hoch/Runter wählt - Leertaste ändert - q geht zurück"
|
msgstr "Hoch/Runter: wählen, Leertaste: ändern, q: zurück"
|
||||||
|
|
||||||
msgid ""
|
msgid "Up/Down: select, Space: switch, a: add, Del: remove, q: back"
|
||||||
"Up/Down select - Space switches - a adds one - Del removes - q goes back"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Hoch/Runter wählt - Leertaste schaltet um - a fügt hinzu - Entf entfernt - q "
|
"Hoch/Runter: wählen, Leertaste: umschalten, a: hinzufügen, Entf: entfernen, "
|
||||||
"geht zurück"
|
"q: zurück"
|
||||||
|
|
||||||
msgid "Usage: bottles-opener [command]"
|
msgid "Usage: bottles-opener [command]"
|
||||||
msgstr "Aufruf: bottles-opener [Befehl]"
|
msgstr "Aufruf: bottles-opener [Befehl]"
|
||||||
@@ -305,8 +304,8 @@ msgstr "Ohne Befehl wird ein interaktives Menü angezeigt."
|
|||||||
msgid "added"
|
msgid "added"
|
||||||
msgstr "hinzugefügt"
|
msgstr "hinzugefügt"
|
||||||
|
|
||||||
msgid "could not be read - is python3 with PyYAML installed?"
|
msgid "could not be read (is python3 with PyYAML installed?)"
|
||||||
msgstr "konnte nicht gelesen werden - ist python3 mit PyYAML installiert?"
|
msgstr "konnte nicht gelesen werden (ist python3 mit PyYAML installiert?)"
|
||||||
|
|
||||||
msgid "double-click"
|
msgid "double-click"
|
||||||
msgstr "Doppelklick"
|
msgstr "Doppelklick"
|
||||||
@@ -317,8 +316,8 @@ msgstr "gerade eben"
|
|||||||
msgid "never"
|
msgid "never"
|
||||||
msgstr "nie"
|
msgstr "nie"
|
||||||
|
|
||||||
msgid "none yet - add one under File types"
|
msgid "none yet, add one under File types"
|
||||||
msgstr "noch keine - unter Dateitypen hinzufügen"
|
msgstr "noch keine, unter Dateitypen hinzufügen"
|
||||||
|
|
||||||
msgid "not found"
|
msgid "not found"
|
||||||
msgstr "nicht gefunden"
|
msgstr "nicht gefunden"
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-39.6 -28.1 596.2 596.2" width="512" height="512">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="glass" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="#5fd0ff"/><stop offset=".45" stop-color="#2aa7e8"/><stop offset="1" stop-color="#0c62a0"/></linearGradient>
|
||||||
|
<linearGradient id="cork" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="#e2ad74"/><stop offset="1" stop-color="#a86f3c"/></linearGradient>
|
||||||
|
<linearGradient id="paper" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#ffffff"/><stop offset="1" stop-color="#e6edf5"/></linearGradient>
|
||||||
|
<filter id="soft" x="-20%" y="-20%" width="140%" height="150%"><feDropShadow dx="0" dy="10" stdDeviation="12" flood-color="#04213a" flood-opacity=".35"/></filter>
|
||||||
|
</defs>
|
||||||
|
<g filter="url(#soft)">
|
||||||
|
<!-- bottle, tilted -->
|
||||||
|
<g transform="translate(40 50) rotate(-24 256 300)">
|
||||||
|
<!-- the file, popping out of the neck: in the bottle's own frame, narrower than the lip -->
|
||||||
|
<path d="M221 12 L269 12 L291 34 L291 128 L221 128 Z" fill="url(#paper)" stroke="#c9d5e3" stroke-width="2.5" stroke-linejoin="round"/>
|
||||||
|
<path d="M269 12 L269 28 C269 31.5 271.5 34 275 34 L291 34 Z" fill="#c9d5e3"/>
|
||||||
|
<rect x="232" y="48" width="38" height="7.5" rx="3.75" fill="#1793d1"/>
|
||||||
|
<rect x="232" y="64" width="48" height="6.5" rx="3.25" fill="#9fb0c4"/>
|
||||||
|
<rect x="232" y="78" width="48" height="6.5" rx="3.25" fill="#9fb0c4"/>
|
||||||
|
<rect x="232" y="92" width="30" height="6.5" rx="3.25" fill="#9fb0c4"/>
|
||||||
|
<path d="M226 128 L226 206 C226 238 166 250 166 300 L166 412 C166 432 182 448 202 448 L310 448 C330 448 346 432 346 412 L346 300 C346 250 286 238 286 206 L286 128 Z" fill="url(#glass)"/>
|
||||||
|
<path d="M196 304 C196 276 212 262 232 254" fill="none" stroke="#fff" stroke-opacity=".55" stroke-width="14" stroke-linecap="round"/>
|
||||||
|
<path d="M196 332 L196 410" stroke="#fff" stroke-opacity=".35" stroke-width="14" stroke-linecap="round"/>
|
||||||
|
<path d="M244 140 L244 196" stroke="#fff" stroke-opacity=".4" stroke-width="8" stroke-linecap="round"/>
|
||||||
|
<rect x="216" y="108" width="80" height="26" rx="9" fill="#0b5a92"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<!-- pop -->
|
||||||
|
<g stroke="#f5a524" stroke-width="12" stroke-linecap="round">
|
||||||
|
<line x1="210" y1="24" x2="222" y2="0"/>
|
||||||
|
<line x1="264" y1="60" x2="292" y2="48"/>
|
||||||
|
<line x1="104" y1="92" x2="78" y2="80"/>
|
||||||
|
<line x1="98" y1="146" x2="70" y2="150"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
@@ -6,7 +6,7 @@ Documentation=man:bottles-opener(1)
|
|||||||
# A bottle that is created or deleted. Where the bottles are depends on how
|
# A bottle that is created or deleted. Where the bottles are depends on how
|
||||||
# Bottles was installed: a distribution package keeps them in the user's data
|
# Bottles was installed: a distribution package keeps them in the user's data
|
||||||
# directory, the Flatpak in its own. A directory that does not exist on this
|
# directory, the Flatpak in its own. A directory that does not exist on this
|
||||||
# system costs nothing - systemd watches the nearest parent that does and picks
|
# system costs nothing: systemd watches the nearest parent that does and picks
|
||||||
# the path up when it appears.
|
# the path up when it appears.
|
||||||
PathModified=%h/.local/share/bottles/bottles
|
PathModified=%h/.local/share/bottles/bottles
|
||||||
PathModified=%h/.var/app/com.usebottles.bottles/data/bottles/bottles
|
PathModified=%h/.var/app/com.usebottles.bottles/data/bottles/bottles
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# bottles-opener - double-click a file and it opens in its Windows program,
|
# bottles-opener: double-click a file and it opens in its Windows program,
|
||||||
# inside its bottle
|
# inside its bottle
|
||||||
#
|
#
|
||||||
# Copyright (C) 2026 Felitendo
|
# Copyright (C) 2026 Felitendo
|
||||||
@@ -35,7 +35,7 @@ fi
|
|||||||
_bo_need_bottles() {
|
_bo_need_bottles() {
|
||||||
bo_installs_detect
|
bo_installs_detect
|
||||||
(( ${#BO_INSTALLS[@]} )) && return 0
|
(( ${#BO_INSTALLS[@]} )) && return 0
|
||||||
bo_bad "$(bo_msg "Bottles is not installed - neither the package nor the Flatpak was found.")"
|
bo_bad "$(bo_msg "Bottles is not installed. Neither the package nor the Flatpak was found.")"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ bo_do_enable() {
|
|||||||
if bo_watch_available; then
|
if bo_watch_available; then
|
||||||
bo_watch_enable || bo_note "$(bo_msg "Could not start the watcher for newly installed programs.")"
|
bo_watch_enable || bo_note "$(bo_msg "Could not start the watcher for newly installed programs.")"
|
||||||
else
|
else
|
||||||
bo_note "$(bo_msg "No systemd user session - newly installed programs will not be picked up on their own.")"
|
bo_note "$(bo_msg "No systemd user session, so newly installed programs will not be picked up on their own.")"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -220,7 +220,7 @@ _bo_find_program() {
|
|||||||
if (( ${#hits[@]} == 0 )); then
|
if (( ${#hits[@]} == 0 )); then
|
||||||
bo_bad "$(bo_msg "No program called \"%s\" was found. \"bottles-opener programs\" lists them all." "$want")"
|
bo_bad "$(bo_msg "No program called \"%s\" was found. \"bottles-opener programs\" lists them all." "$want")"
|
||||||
else
|
else
|
||||||
bo_bad "$(bo_msg "More than one program is called \"%s\" - name the bottle as well." "$want")"
|
bo_bad "$(bo_msg "More than one program is called \"%s\". Name the bottle as well." "$want")"
|
||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -89,7 +89,7 @@ _bo_file_put() {
|
|||||||
local path="$1" content="$2" rc
|
local path="$1" content="$2" rc
|
||||||
|
|
||||||
if ! _bo_owned "$path"; then
|
if ! _bo_owned "$path"; then
|
||||||
bo_bad "$(bo_msg "Not overwriting %s - it was not written by this program." "$path")"
|
bo_bad "$(bo_msg "Not overwriting %s: this program did not write it." "$path")"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ bo_apply() {
|
|||||||
|
|
||||||
# Unreadable looks like empty, and converging on empty removes everything.
|
# Unreadable looks like empty, and converging on empty removes everything.
|
||||||
if [[ -n $BO_SCAN_ERROR ]]; then
|
if [[ -n $BO_SCAN_ERROR ]]; then
|
||||||
bo_bad "$(bo_msg "Bottles could not be read - is python3 with PyYAML installed? Nothing was changed.")"
|
bo_bad "$(bo_msg "Bottles could not be read. Is python3 with PyYAML installed? Nothing was changed.")"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -112,8 +112,8 @@ bo_assoc_compute() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
# A detected type is the default when this program teaches the system the
|
# A detected type is the default when this program teaches the system the
|
||||||
# type - nothing else could open it. A type the system knows already
|
# type, because nothing else could open it. A type the system knows already
|
||||||
# belongs to some application somebody chose, and only gets "Open With".
|
# belongs to an app somebody chose, so it only gets "Open With".
|
||||||
for k in "${!BO_A_EXT[@]}"; do
|
for k in "${!BO_A_EXT[@]}"; do
|
||||||
[[ ${BO_A_STATE[k]} == auto ]] || continue
|
[[ ${BO_A_STATE[k]} == auto ]] || continue
|
||||||
ext="${BO_A_EXT[k]}"
|
ext="${BO_A_EXT[k]}"
|
||||||
|
|||||||
+1
-1
@@ -145,7 +145,7 @@ bo_types_set() {
|
|||||||
mkdir -p "$(dirname "$BO_TYPES")" || return 1
|
mkdir -p "$(dirname "$BO_TYPES")" || return 1
|
||||||
if [[ ! -e $BO_TYPES ]]; then
|
if [[ ! -e $BO_TYPES ]]; then
|
||||||
{
|
{
|
||||||
printf '# %s - file types changed by hand\n' "$BO_PRETTY"
|
printf '# %s: file types changed by hand\n' "$BO_PRETTY"
|
||||||
printf '#\n'
|
printf '#\n'
|
||||||
printf '# Written by `%s`. Nothing here needs editing by hand.\n' "$BO_NAME"
|
printf '# Written by `%s`. Nothing here needs editing by hand.\n' "$BO_NAME"
|
||||||
} > "$BO_TYPES" || return 1
|
} > "$BO_TYPES" || return 1
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
#
|
#
|
||||||
# Writes one icon of a Windows program as PNG to stdout - the largest image of
|
# Writes one icon of a Windows program as PNG to stdout. It picks the largest
|
||||||
# it, the way Explorer would pick it for a big view.
|
# image, like Explorer does for a big view.
|
||||||
#
|
#
|
||||||
# Usage: icon.py <file> [index]
|
# Usage: icon.py <file> [index]
|
||||||
# <file> an .exe or .dll, an .ico, or a .png
|
# <file> an .exe or .dll, an .ico, or a .png
|
||||||
|
|||||||
+4
-4
@@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# The bottle's registry is asked first (scan.py): whatever an installer
|
# The bottle's registry is asked first (scan.py): whatever an installer
|
||||||
# registered there is what Windows would open. This table is for programs
|
# registered there is what Windows would open. This table is for programs
|
||||||
# that registered nothing - portable installs, copied folders.
|
# that registered nothing, like portable installs or copied folders.
|
||||||
|
|
||||||
# Format: <pattern>|<ext>[=<switch>] ...
|
# Format: <pattern>|<ext>[=<switch>] ...
|
||||||
#
|
#
|
||||||
@@ -80,9 +80,9 @@ BO_KNOWN_PROGRAMS=(
|
|||||||
# Format: <ext>|<MIME type>|<description>|<magic>|<generic icon>|<flags>
|
# Format: <ext>|<MIME type>|<description>|<magic>|<generic icon>|<flags>
|
||||||
#
|
#
|
||||||
# <magic>: string:<text> or big32:<hex>, matched at offset 0.
|
# <magic>: string:<text> or big32:<hex>, matched at offset 0.
|
||||||
# <flags>: "own" defines the type even where the system has the extension
|
# <flags>: "own" defines the type even where the system already uses the
|
||||||
# already, as something else - .mpp is Musepack audio there, not a Project
|
# extension for something else. For example, .mpp is Musepack audio there, not
|
||||||
# file. The magic tells the two apart.
|
# a Project file. The magic tells the two apart.
|
||||||
BO_KNOWN_TYPES=(
|
BO_KNOWN_TYPES=(
|
||||||
# Office
|
# Office
|
||||||
"ppa|application/x-ms-powerpoint-addin|PowerPoint add-in||x-office-presentation|"
|
"ppa|application/x-ms-powerpoint-addin|PowerPoint add-in||x-office-presentation|"
|
||||||
|
|||||||
+33
-9
@@ -121,6 +121,26 @@ _bo_row() {
|
|||||||
printf ' %s%*s %s\n' "$label" "$pad" '' "$value"
|
printf ' %s%*s %s\n' "$label" "$pad" '' "$value"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# _bo_fit <width> <words>
|
||||||
|
# As many of the words as fit in width, the rest counted: ".doc .flp +12".
|
||||||
|
_bo_fit() {
|
||||||
|
local width="$1" out='' w n=0 total rest room
|
||||||
|
local -a words
|
||||||
|
read -r -a words <<< "$2"
|
||||||
|
total=${#words[@]}
|
||||||
|
for w in "${words[@]}"; do
|
||||||
|
# Leave room for the count of what does not fit.
|
||||||
|
rest=$(( total - n - 1 ))
|
||||||
|
room=$(( width - ${#out} - (n > 0 ? 1 : 0) - ${#w} ))
|
||||||
|
(( rest > 0 )) && room=$(( room - ${#rest} - 2 ))
|
||||||
|
(( room < 0 )) && break
|
||||||
|
out+="${out:+ }$w"
|
||||||
|
n=$(( n + 1 ))
|
||||||
|
done
|
||||||
|
(( n < total )) && out+="${out:+ }+$(( total - n ))"
|
||||||
|
printf '%s\n' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
_bo_onoff() {
|
_bo_onoff() {
|
||||||
if [[ $1 == yes ]]; then
|
if [[ $1 == yes ]]; then
|
||||||
printf '%s%s%s' "$BO_C_GREEN" "$(bo_msg "ON")" "$BO_C_RESET"
|
printf '%s%s%s' "$BO_C_GREEN" "$(bo_msg "ON")" "$BO_C_RESET"
|
||||||
@@ -165,7 +185,7 @@ _bo_scroll() {
|
|||||||
# bo_ui_status
|
# bo_ui_status
|
||||||
# For `status` and the menu header, from a fresh scan.
|
# For `status` and the menu header, from a fresh scan.
|
||||||
bo_ui_status() {
|
bo_ui_status() {
|
||||||
local last exts nb=0 np install where=''
|
local last exts nb=0 np install where='' cols
|
||||||
|
|
||||||
bo_assoc_compute
|
bo_assoc_compute
|
||||||
bo_assoc_counts
|
bo_assoc_counts
|
||||||
@@ -184,7 +204,7 @@ bo_ui_status() {
|
|||||||
_bo_row "Bottles" "${BO_C_YELLOW}$(bo_msg "not found")${BO_C_RESET}"
|
_bo_row "Bottles" "${BO_C_YELLOW}$(bo_msg "not found")${BO_C_RESET}"
|
||||||
elif [[ -n $BO_SCAN_ERROR ]]; then
|
elif [[ -n $BO_SCAN_ERROR ]]; then
|
||||||
_bo_row "Bottles" \
|
_bo_row "Bottles" \
|
||||||
"${BO_C_RED}$(bo_msg "could not be read - is python3 with PyYAML installed?")${BO_C_RESET}"
|
"${BO_C_RED}$(bo_msg "could not be read (is python3 with PyYAML installed?)")${BO_C_RESET}"
|
||||||
else
|
else
|
||||||
_bo_row "Bottles" "$where"
|
_bo_row "Bottles" "$where"
|
||||||
fi
|
fi
|
||||||
@@ -197,11 +217,15 @@ bo_ui_status() {
|
|||||||
_bo_row "$(bo_msg "Programs found")" "$(bo_msg "%d in %d bottles" "$np" "$nb")"
|
_bo_row "$(bo_msg "Programs found")" "$(bo_msg "%d in %d bottles" "$np" "$nb")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exts="$(bo_assoc_active_exts 10)"
|
# On one line: the value starts in column 34 of at most 80.
|
||||||
|
cols="$(tput cols 2>/dev/null)" || cols=80
|
||||||
|
[[ $cols =~ ^[0-9]+$ ]] || cols=80
|
||||||
|
(( cols > 80 )) && cols=80
|
||||||
|
exts="$(_bo_fit $(( cols - 35 )) "$(bo_assoc_active_exts)")"
|
||||||
if (( BO_N_ACTIVE )); then
|
if (( BO_N_ACTIVE )); then
|
||||||
_bo_row "$(bo_msg "File types")" "$exts"
|
_bo_row "$(bo_msg "File types")" "$exts"
|
||||||
else
|
else
|
||||||
_bo_row "$(bo_msg "File types")" "${BO_C_DIM}$(bo_msg "none yet - add one under File types")${BO_C_RESET}"
|
_bo_row "$(bo_msg "File types")" "${BO_C_DIM}$(bo_msg "none yet, add one under File types")${BO_C_RESET}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if bo_watch_available; then
|
if bo_watch_available; then
|
||||||
@@ -250,7 +274,7 @@ bo_ui_settings() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
bo_msg_into "Settings"; title="$BO_MSG_RESULT"
|
bo_msg_into "Settings"; title="$BO_MSG_RESULT"
|
||||||
bo_msg_into "Up/Down select - Space changes - q goes back"
|
bo_msg_into "Up/Down: select, Space: change, q: back"
|
||||||
hint="$BO_MSG_RESULT"
|
hint="$BO_MSG_RESULT"
|
||||||
|
|
||||||
_bo_clearseq
|
_bo_clearseq
|
||||||
@@ -327,7 +351,7 @@ bo_ui_pick_program() {
|
|||||||
labels+=("$BO_LABEL")
|
labels+=("$BO_LABEL")
|
||||||
done
|
done
|
||||||
|
|
||||||
bo_msg_into "Up/Down select - Enter picks - q cancels"
|
bo_msg_into "Up/Down: select, Enter: pick, q: cancel"
|
||||||
hint="$BO_MSG_RESULT"
|
hint="$BO_MSG_RESULT"
|
||||||
_bo_clearseq
|
_bo_clearseq
|
||||||
_bo_term_rows 7
|
_bo_term_rows 7
|
||||||
@@ -416,7 +440,7 @@ bo_ui_programs() {
|
|||||||
local -a labels=() pexts=()
|
local -a labels=() pexts=()
|
||||||
|
|
||||||
bo_msg_into "Programs"; title="$BO_MSG_RESULT"
|
bo_msg_into "Programs"; title="$BO_MSG_RESULT"
|
||||||
bo_msg_into "Up/Down select - Enter edits its file types - q goes back"
|
bo_msg_into "Up/Down: select, Enter: edit file types, q: back"
|
||||||
hint="$BO_MSG_RESULT"
|
hint="$BO_MSG_RESULT"
|
||||||
bo_msg_into "No programs found in any bottle."; empty="$BO_MSG_RESULT"
|
bo_msg_into "No programs found in any bottle."; empty="$BO_MSG_RESULT"
|
||||||
|
|
||||||
@@ -501,11 +525,11 @@ bo_ui_types() {
|
|||||||
local l_default l_openwith l_off l_missing l_added
|
local l_default l_openwith l_off l_missing l_added
|
||||||
|
|
||||||
bo_msg_into "File types"; title="$BO_MSG_RESULT"
|
bo_msg_into "File types"; title="$BO_MSG_RESULT"
|
||||||
bo_msg_into "Up/Down select - Space switches - a adds one - Del removes - q goes back"
|
bo_msg_into "Up/Down: select, Space: switch, a: add, Del: remove, q: back"
|
||||||
hint="$BO_MSG_RESULT"
|
hint="$BO_MSG_RESULT"
|
||||||
bo_msg_into "\"double-click\" opens it; \"Open With\" only lists the program there."
|
bo_msg_into "\"double-click\" opens it; \"Open With\" only lists the program there."
|
||||||
legend="$BO_MSG_RESULT"
|
legend="$BO_MSG_RESULT"
|
||||||
bo_msg_into "File opening is off - this is what it would do."
|
bo_msg_into "File opening is off. This is what it would do."
|
||||||
warn="$BO_MSG_RESULT"
|
warn="$BO_MSG_RESULT"
|
||||||
bo_msg_into "No file types yet. Press a to add one."
|
bo_msg_into "No file types yet. Press a to add one."
|
||||||
empty="$BO_MSG_RESULT"
|
empty="$BO_MSG_RESULT"
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
#
|
#
|
||||||
# Lists the bottles and programs of one Bottles installation, and the file
|
# Lists the bottles and programs of one Bottles installation, and the file
|
||||||
# types each program registered in its bottle's registry - the way Windows
|
# types each program registered in its bottle's registry. That is how Windows
|
||||||
# knows them: extension -> ProgID -> open command, icon and description.
|
# knows them: extension -> ProgID -> open command, icon and description.
|
||||||
#
|
#
|
||||||
# Runs on the host, or inside the Bottles Flatpak fed through stdin, so it only
|
# Runs on the host, or inside the Bottles Flatpak fed through stdin, so it only
|
||||||
|
|||||||
Reference in new issue
Block a user