Skip to content

Commit 2e392a0

Browse files
committed
nemo-action.c: Allow absolute path pattern matching for File and
Location filters. Rewrite File and Location descriptions in the sample action.
1 parent 3fc6c6e commit 2e392a0

2 files changed

Lines changed: 78 additions & 54 deletions

File tree

files/usr/share/nemo/actions/sample.nemo_action

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -124,52 +124,36 @@ Extensions=any;
124124

125125
#UriScheme=file
126126

127-
# Locations - semicolor-separated array of directory names and globs to check against the
128-
# selection's parent location.
127+
# Locations and Files - semicolon-separated arrays of globs, filenames and paths to be tested
128+
# against the current location or selection, respectively.
129129
#
130-
# If Locations is defined, an action will *only* be valid under one of the following conditions:
131-
# - The current location's filename (foo.bar, no path) is captured by *at least one*
132-
# of any defined glob patterns.
133-
# - The current location's filename exactly matches *at least one* defined filename.
130+
# - Globs and paths can be relative or absolute.
131+
# - ~ will be expanded at runtime to the user's home directory.
132+
# - Absolute paths will be tested against the file/location's full path. Otherwise it is tested
133+
# against the filename only.
134+
# - A glob with a leading * will be matched against the full path, whether it contains additional
135+
# path parts or is just a partial filename.
136+
# - If a condition is prefixed with a ! it will be considered an opposing condition (If the file
137+
# passes this test, action is forbidden).
138+
# - Allowed patterns are considered before forbidden ones. This allows behaviors such as:
134139
#
135-
# If an entry is prefixed with '!', the above conditions are reversed, and an action is
136-
# considered *invalid* if any matches are made.
140+
# # Allow any dot-file except .config
141+
# Locations=.*;!.config
137142
#
138-
# NOTE: Allowed patterns are considered before forbidden ones. This means that a location
139-
# would be invalidated by not matching any allowed patterns before being invalidated
140-
# by matching forbidden ones.
141-
#
142-
# Example desired condition: Match any dot-file locations except '.config':
143-
#
144-
# Locations=.*;!.config
143+
144+
# Locations - semicolon-separated array of globs to check against the currently location.
145145
#
146-
# Action would be visible when right-clicking the file '.foo/bar', but not '.config/bar'
146+
# The current location must match at least one 'allowed' pattern, path or name for the action
147+
# to be considered valid.
147148
#
148149
# Optional
149150

150151
#Locations=.*;!.config;
151152

152-
# Files - semicolor-separated array of file names and globs to check against the currently
153-
# selected file list.
154-
#
155-
# If Files is defined, an action will *only* be valid under the following conditions:
156-
# - All selected filenames (foo.bar, no path) are captured by *at least one* of any
157-
# defined glob patterns.
158-
# - All file absolute paths exactly match *at least one* of any defined absolute paths.
159-
# - All filenames exactly match *at least one* of the defined filenames.
160-
#
161-
# If an entry is prefixed with '!', the above conditions are reversed, and an action is
162-
# considered *invalid* if any matches are made.
163-
#
164-
# NOTE: Allowed patterns are considered before forbidden ones. This means that a filename
165-
# would be invalidated by not matching any allowed patterns before being invalidated
166-
# by matching forbidden ones.
167-
#
168-
# Example desired condition: Match .bash* but not '.bashrc':
169-
#
170-
# Files=.bash*;!.bashrc;
153+
# Files - semicolon-separated array of globs to check against the currently selected files.
171154
#
172-
# Action would be visible when right-clicking the file '.bash_history', but not '.bashrc'
155+
# All files in the selection must match at least one 'allowed' pattern, path or name for
156+
# the action to be considered valid.
173157
#
174158
# Optional
175159

libnemo-private/nemo-action.c

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ typedef struct {
133133
guint handler_id;
134134
} GSettingsCondition;
135135

136+
typedef struct {
137+
GPatternSpec *pattern;
138+
gboolean absolute;
139+
} MatchPattern;
140+
136141
static void
137142
dbus_condition_free (gpointer data)
138143
{
@@ -157,6 +162,29 @@ gsettings_condition_free (gpointer data)
157162
g_free (cond);
158163
}
159164

165+
static MatchPattern *
166+
new_match_pattern (const gchar *pattern)
167+
{
168+
MatchPattern *mp = g_new0 (MatchPattern, 1);
169+
170+
mp->pattern = g_pattern_spec_new (pattern);
171+
172+
// A pattern with a leading * can be matched against a full path, whether it has
173+
// any other path elements or not (*/foo/bar/* or *.foo)
174+
mp->absolute = g_str_has_prefix (pattern, "/") || g_str_has_prefix (pattern, "*");
175+
176+
return mp;
177+
}
178+
179+
static void
180+
free_match_pattern (gpointer data)
181+
{
182+
MatchPattern *mp = (MatchPattern *) data;
183+
184+
g_pattern_spec_free (mp->pattern);
185+
g_free (mp);
186+
}
187+
160188
static void
161189
nemo_action_init (NemoAction *action)
162190
{
@@ -580,23 +608,29 @@ populate_patterns_and_filenames (NemoAction *action,
580608
gint i;
581609

582610
for (i = 0; i < g_strv_length (array); i++) {
583-
const gchar *str = array[i];
611+
GString *str = g_string_new (array[i]);
612+
613+
g_string_replace (str, "~", g_get_home_dir (), 1);
614+
615+
g_printerr ("str: '%s'\n", str->str);
584616

585-
if (g_strstr_len (str, -1, "?") || g_strstr_len (str, -1, "*")) {
586-
if (g_str_has_prefix (array[i], "!")) {
587-
*forbidden_patterns = g_list_prepend (*forbidden_patterns, g_pattern_spec_new (array[i] + 1));
617+
if (g_strstr_len (str->str, -1, "?") || g_strstr_len (str->str, -1, "*")) {
618+
if (g_str_has_prefix (str->str, "!")) {
619+
*forbidden_patterns = g_list_prepend (*forbidden_patterns, new_match_pattern (str->str + 1));
588620
} else {
589-
*allowed_patterns = g_list_prepend (*allowed_patterns, g_pattern_spec_new (array[i]));
621+
*allowed_patterns = g_list_prepend (*allowed_patterns, new_match_pattern (str->str));
590622
}
591-
592-
continue;
593623
}
594-
595-
if (g_str_has_prefix (array[i], "!")) {
596-
*forbidden_filenames = g_list_prepend (*forbidden_filenames, g_strdup (array[i] + 1));
597-
} else {
598-
*allowed_filenames = g_list_prepend (*allowed_filenames, g_strdup (array[i]));
624+
else
625+
{
626+
if (g_str_has_prefix (str->str, "!")) {
627+
*forbidden_filenames = g_list_prepend (*forbidden_filenames, g_strdup (str->str + 1));
628+
} else {
629+
*allowed_filenames = g_list_prepend (*allowed_filenames, g_strdup (str->str));
630+
}
599631
}
632+
633+
g_string_free (str, TRUE);
600634
}
601635

602636
*allowed_patterns = g_list_reverse (*allowed_patterns);
@@ -991,10 +1025,10 @@ nemo_action_finalize (GObject *object)
9911025
g_list_free_full (priv->dbus, (GDestroyNotify) dbus_condition_free);
9921026
g_list_free_full (priv->gsettings, (GDestroyNotify) gsettings_condition_free);
9931027

994-
g_list_free_full (priv->allowed_location_patterns, (GDestroyNotify) g_pattern_spec_free);
995-
g_list_free_full (priv->forbidden_location_patterns, (GDestroyNotify) g_pattern_spec_free);
996-
g_list_free_full (priv->allowed_patterns, (GDestroyNotify) g_pattern_spec_free);
997-
g_list_free_full (priv->forbidden_patterns, (GDestroyNotify) g_pattern_spec_free);
1028+
g_list_free_full (priv->allowed_location_patterns, (GDestroyNotify) free_match_pattern);
1029+
g_list_free_full (priv->forbidden_location_patterns, (GDestroyNotify) free_match_pattern);
1030+
g_list_free_full (priv->allowed_patterns, (GDestroyNotify) free_match_pattern);
1031+
g_list_free_full (priv->forbidden_patterns, (GDestroyNotify) free_match_pattern);
9981032
g_list_free_full (priv->allowed_location_filenames, (GDestroyNotify) g_free);
9991033
g_list_free_full (priv->forbidden_location_filenames, (GDestroyNotify) g_free);
10001034
g_list_free_full (priv->allowed_filenames, (GDestroyNotify) g_free);
@@ -1686,7 +1720,10 @@ check_is_allowed (NemoAction *action,
16861720
allowed_allowed = FALSE;
16871721

16881722
for (ll = allowed_patterns; ll != NULL; ll = ll->next) {
1689-
if (g_pattern_spec_match ((GPatternSpec *) ll->data, strlen (name), name, NULL)) {
1723+
MatchPattern *mp = (MatchPattern *) ll->data;
1724+
const gchar *test_str = mp->absolute ? path : name;
1725+
1726+
if (g_pattern_spec_match (mp->pattern, strlen (test_str), test_str, NULL)) {
16901727
allowed_allowed = TRUE;
16911728
break;
16921729
}
@@ -1711,7 +1748,10 @@ check_is_allowed (NemoAction *action,
17111748
// (forbidden_allowed = TRUE;)
17121749

17131750
for (ll = forbidden_patterns; ll != NULL; ll = ll->next) {
1714-
if (g_pattern_spec_match ((GPatternSpec *) ll->data, strlen (name), name, NULL)) {
1751+
MatchPattern *mp = (MatchPattern *) ll->data;
1752+
const gchar *test_str = mp->absolute ? path : name;
1753+
1754+
if (g_pattern_spec_match (mp->pattern, strlen (test_str), test_str, NULL)) {
17151755
forbidden_allowed = FALSE;
17161756
break;
17171757
}

0 commit comments

Comments
 (0)