diff --git a/.eslintignore b/.eslintignore
index 7e8d61e..c98486f 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -3,3 +3,4 @@ install/
flatpak/
node_modules/
repo/
+src/wordwrap.js
diff --git a/.prettierignore b/.prettierignore
index 7e8d61e..c98486f 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -3,3 +3,4 @@ install/
flatpak/
node_modules/
repo/
+src/wordwrap.js
diff --git a/TODO.md b/TODO.md
index 9d92bfd..778580b 100644
--- a/TODO.md
+++ b/TODO.md
@@ -15,3 +15,4 @@
14. [ ] detect non imperative mood
https://tekin.co.uk/2020/03/git-commit-verbose-mode
+https://wiki.gnome.org/Git/CommitMessages
diff --git a/data/re.sonny.Commit.gschema.xml b/data/re.sonny.Commit.gschema.xml
index f4d5d6b..14d7712 100644
--- a/data/re.sonny.Commit.gschema.xml
+++ b/data/re.sonny.Commit.gschema.xml
@@ -6,6 +6,13 @@
Message title length hint
+
+
+ 75
+
+ Message body length wrap
+
+
false
Use dark mode
diff --git a/re.sonny.Commit.json b/re.sonny.Commit.json
index 951d60c..87e1d39 100644
--- a/re.sonny.Commit.json
+++ b/re.sonny.Commit.json
@@ -87,7 +87,7 @@
"sources": [
{
"type": "dir",
- "path": "./"
+ "path": "."
}
]
}
diff --git a/src/Editor.js b/src/CommitEditor.js
similarity index 89%
rename from src/Editor.js
rename to src/CommitEditor.js
index 1f69811..9e8ecef 100644
--- a/src/Editor.js
+++ b/src/CommitEditor.js
@@ -6,7 +6,7 @@ import Adw from "gi://Adw";
import { relativePath } from "./util.js";
-const file = Gio.File.new_for_path(relativePath("./Editor.ui"));
+const file = Gio.File.new_for_path(relativePath("./CommitEditor.ui"));
const [, template] = file.load_contents(null);
const scheme_manager = GtkSource.StyleSchemeManager.get_default();
@@ -19,7 +19,7 @@ language_manager.set_search_path([
export default GObject.registerClass(
{
- GTypeName: "Editor",
+ GTypeName: "CommitEditor",
Properties: {
language: GObject.ParamSpec.string(
"language",
@@ -35,7 +35,7 @@ export default GObject.registerClass(
"style-updated": {},
},
},
- class Editor extends Gtk.ScrolledWindow {
+ class CommitEditor extends Gtk.ScrolledWindow {
_init(params = {}) {
super._init(params);
diff --git a/src/CommitEditor.ui b/src/CommitEditor.ui
new file mode 100644
index 0000000..9d2a9b0
--- /dev/null
+++ b/src/CommitEditor.ui
@@ -0,0 +1,24 @@
+
+
+
+ true
+
+
+
+
+
diff --git a/src/Editor.ui b/src/Editor.ui
deleted file mode 100644
index e75ed21..0000000
--- a/src/Editor.ui
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
- true
-
-
-
-
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
- word
- 6
- 6
- 6
- 6
-
- GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_WORD_COMPLETION |
- GTK_INPUT_HINT_EMOJI | GTK_INPUT_HINT_UPPERCASE_SENTENCES
-
-
-
-
-
diff --git a/src/application.js b/src/application.js
index 3ef7103..9db3b7b 100644
--- a/src/application.js
+++ b/src/application.js
@@ -111,7 +111,7 @@ function openEditor({ file, application, readonly }) {
try {
[, commitMessage] = GLib.file_get_contents(filePath);
} catch (err) {
- printerr(err);
+ logError(err);
application.quit();
return;
}
diff --git a/src/editor.js b/src/editor.js
index acec278..2e41dfd 100644
--- a/src/editor.js
+++ b/src/editor.js
@@ -2,10 +2,10 @@ import Gtk from "gi://Gtk";
import GLib from "gi://GLib";
import GtkSource from "gi://GtkSource";
-import Editor from "./Editor.js";
+import CommitEditor from "./CommitEditor.js";
import { settings } from "./util.js";
-import { parse, hasCommitMessage } from "./scm.js";
+import { hasCommitMessage } from "./scm.js";
const HIGHLIGHT_BACKGROUND_TAG_NAME = "highlightBackground";
@@ -13,19 +13,9 @@ export default function editor({
builder,
commitButton,
type,
- commitMessage,
window,
+ parsed,
}) {
- let parsed = {};
-
- try {
- parsed = parse(commitMessage, type);
- } catch (err) {
- if (__DEV__) {
- logError(err);
- }
- }
-
const {
body,
comment,
@@ -51,7 +41,7 @@ export default function editor({
let previousNumberOfLinesInCommitMessage = 1;
const main = builder.get_object("main");
- const widget = new Editor({ language });
+ const widget = new CommitEditor({ language });
main.append(widget);
const source_view = widget.view;
diff --git a/src/main.js b/src/main.js
index c8cfcab..129a0a2 100644
--- a/src/main.js
+++ b/src/main.js
@@ -52,4 +52,4 @@ export default function main(argv, { version, datadir }) {
}
return application.run(argv);
-}
+}
diff --git a/src/scm.js b/src/scm.js
index f2f7d6d..458d3df 100644
--- a/src/scm.js
+++ b/src/scm.js
@@ -68,6 +68,8 @@ export function parse(commit, type) {
capitalize = true;
}
+ log(type);
+
return {
body,
comment,
@@ -78,6 +80,13 @@ export function parse(commit, type) {
read_only_index,
language,
capitalize,
+ wrap: [
+ "hg",
+ "commit",
+ "git-merge-squash",
+ "git-rebase-squash",
+ "merge",
+ ].includes(type),
};
}
diff --git a/src/welcome.js b/src/welcome.js
index 65ccebd..da779d0 100644
--- a/src/welcome.js
+++ b/src/welcome.js
@@ -12,15 +12,26 @@ export default function Welcome({ application }) {
loadStyleSheet(relativePath("./style.css"));
- const spinButton = builder.get_object("spinButton");
- spinButton.set_range(50, 200);
- spinButton.set_increments(1, 10);
+ const button_hint = builder.get_object("button_hint");
+ button_hint.set_range(50, 200);
+ button_hint.set_increments(1, 10);
settings.bind(
"title-length-hint",
- spinButton,
+ button_hint,
"value",
Gio.SettingsBindFlags.DEFAULT,
);
+
+ const button_wrap = builder.get_object("button_wrap");
+ button_wrap.set_range(72, 200);
+ button_wrap.set_increments(1, 10);
+ settings.bind(
+ "body-length-wrap",
+ button_wrap,
+ "value",
+ Gio.SettingsBindFlags.DEFAULT,
+ );
+
const darkSwitch = builder.get_object("darkSwitch");
Adw.StyleManager.get_default().bind_property(
"dark",
diff --git a/src/welcome.ui b/src/welcome.ui
index 9837954..1bbf227 100644
--- a/src/welcome.ui
+++ b/src/welcome.ui
@@ -30,11 +30,30 @@
Message title length hint
+ >Commit title max length
-
+
50
- True
+ true
+ center
+
+
+
+
+
+
+
+
+
+
+ Message body max length
+
+
+ 75
+ true
center
diff --git a/src/window.js b/src/window.js
index 381f000..bb06f35 100644
--- a/src/window.js
+++ b/src/window.js
@@ -5,6 +5,8 @@ import Gio from "gi://Gio";
import Editor from "./editor.js";
import { relativePath } from "./util.js";
+import { parse } from "./scm.js";
+import wordwrap from "./wordwrap.js";
export default function Window({
application,
@@ -13,12 +15,28 @@ export default function Window({
type,
readonly,
}) {
- const builder = Gtk.Builder.new_from_file(relativePath("./window.ui"));
+ let parsed = {};
+ try {
+ parsed = parse(commitMessage, type);
+ } catch (err) {
+ if (__DEV__) {
+ logError(err);
+ }
+ }
+ const builder = Gtk.Builder.new_from_file(relativePath("./window.ui"));
const window = builder.get_object("window");
const cancelButton = builder.get_object("cancelButton");
const commitButton = builder.get_object("commitButton");
+ const { buffer, source_view } = Editor({
+ builder,
+ commitButton,
+ type,
+ window,
+ parsed,
+ });
+
window.set_application(application);
const cancelAction = new Gio.SimpleAction({
@@ -26,7 +44,8 @@ export default function Window({
parameter_type: null,
});
cancelAction.connect("activate", () => {
- save({ file, application, value: "", readonly });
+ log(parsed);
+ save({ file, window, value: "", readonly });
});
window.add_action(cancelAction);
@@ -35,33 +54,31 @@ export default function Window({
parameter_type: null,
});
commitAction.connect("activate", () => {
- const value = buffer.text;
- save({ file, application, value, readonly });
+ const { text } = buffer;
+ const value = parsed.wrap ? wordwrap(0, 75, { mode: "hard" })(text) : text;
+ save({
+ file,
+ window,
+ value,
+ readonly,
+ });
});
window.add_action(commitAction);
- const { buffer, source_view } = Editor({
- builder,
- commitButton,
- type,
- commitMessage,
- window,
- });
-
// https://github.com/sonnyp/Commit/issues/33
window.set_focus(source_view);
return { window, cancelButton, commitButton, buffer };
}
-function save({ file, value, application, readonly }) {
+function save({ file, value, window, readonly }) {
if (!readonly) {
try {
GLib.file_set_contents(file.get_path(), value);
} catch (err) {
- printerr(err);
+ logError(err);
}
}
- application.quit();
+ window.close();
}
diff --git a/src/wordwrap.js b/src/wordwrap.js
new file mode 100644
index 0000000..65f1821
--- /dev/null
+++ b/src/wordwrap.js
@@ -0,0 +1,89 @@
+// This software is released under the MIT license:
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+// the Software, and to permit persons to whom the Software is furnished to do so,
+// subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+export default function wordwrap (start, stop, params) {
+ if (typeof start === 'object') {
+ params = start;
+ start = params.start;
+ stop = params.stop;
+ }
+
+ if (typeof stop === 'object') {
+ params = stop;
+ start = start || params.start;
+ stop = undefined;
+ }
+
+ if (!stop) {
+ stop = start;
+ start = 0;
+ }
+
+ if (!params) params = {};
+ var mode = params.mode || 'soft';
+ var re = mode === 'hard' ? /\b/ : /(\S+\s+)/;
+
+ return function (text) {
+ var chunks = text.toString()
+ .split(re)
+ .reduce(function (acc, x) {
+ if (mode === 'hard') {
+ for (var i = 0; i < x.length; i += stop - start) {
+ acc.push(x.slice(i, i + stop - start));
+ }
+ }
+ else acc.push(x)
+ return acc;
+ }, [])
+ ;
+
+ return chunks.reduce(function (lines, rawChunk) {
+ if (rawChunk === '') return lines;
+
+ var chunk = rawChunk.replace(/\t/g, ' ');
+
+ var i = lines.length - 1;
+ if (lines[i].length + chunk.length > stop) {
+ lines[i] = lines[i].replace(/\s+$/, '');
+
+ chunk.split(/\n/).forEach(function (c) {
+ lines.push(
+ new Array(start + 1).join(' ')
+ + c.replace(/^\s+/, '')
+ );
+ });
+ }
+ else if (chunk.match(/\n/)) {
+ var xs = chunk.split(/\n/);
+ lines[i] += xs.shift();
+ xs.forEach(function (c) {
+ lines.push(
+ new Array(start + 1).join(' ')
+ + c.replace(/^\s+/, '')
+ );
+ });
+ }
+ else {
+ lines[i] += chunk;
+ }
+
+ return lines;
+ }, [ new Array(start + 1).join(' ') ]).join('\n');
+ };
+};