commands.c 17.3 KB
Newer Older
Moritz Lipp's avatar
Moritz Lipp committed
1 2
/* See LICENSE file for license and copyright information */

Moritz Lipp's avatar
Moritz Lipp committed
3
#include <string.h>
4
#include <stdlib.h>
5
#include <glib/gi18n.h>
Moritz Lipp's avatar
Moritz Lipp committed
6

Moritz Lipp's avatar
Moritz Lipp committed
7
#include "commands.h"
Moritz Lipp's avatar
Moritz Lipp committed
8
#include "shortcuts.h"
9 10
#include "bookmarks.h"
#include "database.h"
Moritz Lipp's avatar
Moritz Lipp committed
11
#include "document.h"
Moritz Lipp's avatar
Moritz Lipp committed
12
#include "zathura.h"
13
#include "print.h"
14
#include "document.h"
Moritz Lipp's avatar
Moritz Lipp committed
15
#include "utils.h"
16
#include "page-widget.h"
Moritz Lipp's avatar
Moritz Lipp committed
17
#include "page.h"
Moritz Lipp's avatar
Moritz Lipp committed
18
#include "plugin.h"
19
#include "internal.h"
Moritz Lipp's avatar
Moritz Lipp committed
20
#include "render.h"
21
#include "adjustment.h"
Moritz Lipp's avatar
Moritz Lipp committed
22

23
#include <girara/session.h>
Moritz Lipp's avatar
Moritz Lipp committed
24
#include <girara/settings.h>
Moritz Lipp's avatar
Moritz Lipp committed
25
#include <girara/commands.h>
26
#include <girara/datastructures.h>
Sebastian Ramacher's avatar
Sebastian Ramacher committed
27
#include <girara/utils.h>
28

Moritz Lipp's avatar
Moritz Lipp committed
29
bool
30
cmd_bookmark_create(girara_session_t* session, girara_list_t* argument_list)
Moritz Lipp's avatar
Moritz Lipp committed
31
{
32 33 34 35
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  if (zathura->document == NULL) {
36
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
37 38 39 40 41
    return false;
  }

  const unsigned int argc = girara_list_size(argument_list);
  if (argc != 1) {
42
    girara_notify(session, GIRARA_ERROR, _("Invalid number of arguments given."));
43 44 45 46 47
    return false;
  }

  const char* bookmark_name = girara_list_nth(argument_list, 0);
  zathura_bookmark_t* bookmark = zathura_bookmark_get(zathura, bookmark_name);
48
  bool update = bookmark != NULL ? true : false;
49

50
  bookmark = zathura_bookmark_add(zathura, bookmark_name, zathura_document_get_current_page_number(zathura->document) + 1);
51
  if (bookmark == NULL) {
52 53 54 55 56
    if (update == true) {
      girara_notify(session, GIRARA_ERROR, _("Could not update bookmark: %s"), bookmark_name);
    } else {
      girara_notify(session, GIRARA_ERROR, _("Could not create bookmark: %s"), bookmark_name);
    }
57
    return false;
58 59 60 61 62 63
  } else {
    if (update == true) {
      girara_notify(session, GIRARA_INFO, _("Bookmark successfully updated: %s"), bookmark_name);
    } else {
      girara_notify(session, GIRARA_INFO, _("Bookmark successfully created: %s"), bookmark_name);
    }
64 65
  }

Moritz Lipp's avatar
Moritz Lipp committed
66 67 68 69
  return true;
}

bool
Moritz Lipp's avatar
Moritz Lipp committed
70
cmd_bookmark_delete(girara_session_t* session, girara_list_t* argument_list)
Moritz Lipp's avatar
Moritz Lipp committed
71
{
72 73 74 75
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  if (zathura->document == NULL) {
76
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
77 78 79 80 81
    return false;
  }

  const unsigned int argc = girara_list_size(argument_list);
  if (argc != 1) {
82
    girara_notify(session, GIRARA_ERROR, _("Invalid number of arguments given."));
83 84 85 86 87
    return false;
  }

  const char* bookmark = girara_list_nth(argument_list, 0);
  if (zathura_bookmark_remove(zathura, bookmark)) {
88
    girara_notify(session, GIRARA_INFO, _("Removed bookmark: %s"), bookmark);
89
  } else {
90
    girara_notify(session, GIRARA_ERROR, _("Failed to remove bookmark: %s"), bookmark);
91 92
  }

Moritz Lipp's avatar
Moritz Lipp committed
93 94 95 96
  return true;
}

bool
Sebastian Ramacher's avatar
Sebastian Ramacher committed
97
cmd_bookmark_open(girara_session_t* session, girara_list_t* argument_list)
Moritz Lipp's avatar
Moritz Lipp committed
98
{
Sebastian Ramacher's avatar
Sebastian Ramacher committed
99 100 101 102
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  if (zathura->document == NULL) {
103
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
Sebastian Ramacher's avatar
Sebastian Ramacher committed
104 105 106 107 108
    return false;
  }

  const unsigned int argc = girara_list_size(argument_list);
  if (argc != 1) {
109 110
    GString* string = g_string_new(NULL);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
111
    GIRARA_LIST_FOREACH_BODY(zathura->bookmarks.bookmarks, zathura_bookmark_t*, bookmark,
112
      g_string_append_printf(string, "<b>%s</b>: %u\n", bookmark->id, bookmark->page);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
113
    );
114 115 116 117 118 119 120 121 122

    if (strlen(string->str) > 0) {
      g_string_erase(string, strlen(string->str) - 1, 1);
      girara_notify(session, GIRARA_INFO, "%s", string->str);
    } else {
      girara_notify(session, GIRARA_INFO, _("No bookmarks available."));
    }

    g_string_free(string, TRUE);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
123 124 125 126 127 128
    return false;
  }

  const char* bookmark_name = girara_list_nth(argument_list, 0);
  zathura_bookmark_t* bookmark = zathura_bookmark_get(zathura, bookmark_name);
  if (bookmark == NULL) {
129
    girara_notify(session, GIRARA_ERROR, _("No such bookmark: %s"), bookmark_name);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
130 131 132
    return false;
  }

133
  zathura_jumplist_add(zathura);
134
  page_set(zathura, bookmark->page - 1);
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
135
  if (bookmark->x != DBL_MIN && bookmark->y != DBL_MIN) {
136
    position_set(zathura, bookmark->x, bookmark->y);
Sebastian Ramacher's avatar
CS  
Sebastian Ramacher committed
137
  }
138 139 140
  zathura_jumplist_add(zathura);

  return true;
Moritz Lipp's avatar
Moritz Lipp committed
141 142 143
}

bool
144
cmd_close(girara_session_t* session, girara_list_t* UNUSED(argument_list))
Moritz Lipp's avatar
Moritz Lipp committed
145
{
146 147 148
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
149 150 151
  if (zathura->document == NULL) {
    return true;
  }
152

Moritz Lipp's avatar
Moritz Lipp committed
153
  document_close(zathura, false);
Moritz Lipp's avatar
Moritz Lipp committed
154

Moritz Lipp's avatar
Moritz Lipp committed
155 156 157 158
  return true;
}

bool
Moritz Lipp's avatar
Moritz Lipp committed
159
cmd_info(girara_session_t* session, girara_list_t* UNUSED(argument_list))
Moritz Lipp's avatar
Moritz Lipp committed
160
{
Moritz Lipp's avatar
Moritz Lipp committed
161 162 163 164
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  if (zathura->document == NULL) {
165
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
Moritz Lipp's avatar
Moritz Lipp committed
166 167 168 169 170
    return false;
  }

  struct meta_field {
    char* name;
171
    zathura_document_information_type_t field;
Moritz Lipp's avatar
Moritz Lipp committed
172 173
  };

174 175 176 177 178 179 180 181 182
  const struct meta_field meta_fields[] = {
    { _("Title"),             ZATHURA_DOCUMENT_INFORMATION_TITLE },
    { _("Author"),            ZATHURA_DOCUMENT_INFORMATION_AUTHOR },
    { _("Subject"),           ZATHURA_DOCUMENT_INFORMATION_SUBJECT },
    { _("Keywords"),          ZATHURA_DOCUMENT_INFORMATION_KEYWORDS },
    { _("Creator"),           ZATHURA_DOCUMENT_INFORMATION_CREATOR },
    { _("Producer"),          ZATHURA_DOCUMENT_INFORMATION_PRODUCER },
    { _("Creation date"),     ZATHURA_DOCUMENT_INFORMATION_CREATION_DATE },
    { _("Modification date"), ZATHURA_DOCUMENT_INFORMATION_MODIFICATION_DATE }
Moritz Lipp's avatar
Moritz Lipp committed
183 184
  };

185 186 187 188
  girara_list_t* information = zathura_document_get_information(zathura->document, NULL);
  if (information == NULL) {
    girara_notify(session, GIRARA_INFO, _("No information available."));
    return false;
Moritz Lipp's avatar
Moritz Lipp committed
189 190
  }

191
  GString* string = g_string_new(NULL);
Moritz Lipp's avatar
Moritz Lipp committed
192

Sebastian Ramacher's avatar
Sebastian Ramacher committed
193 194 195 196 197 198
  GIRARA_LIST_FOREACH_BODY(information, zathura_document_information_entry_t*, entry,
    if (entry != NULL) {
      for (unsigned int i = 0; i < LENGTH(meta_fields); i++) {
        if (meta_fields[i].field == entry->type) {
          g_string_append_printf(string, "<b>%s:</b> %s\n", meta_fields[i].name, entry->value);
        }
199
      }
Moritz Lipp's avatar
Moritz Lipp committed
200
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
201
  );
Moritz Lipp's avatar
Moritz Lipp committed
202 203 204

  if (strlen(string->str) > 0) {
    g_string_erase(string, strlen(string->str) - 1, 1);
205
    girara_notify(session, GIRARA_INFO, "%s", string->str);
206 207
  } else {
    girara_notify(session, GIRARA_INFO, _("No information available."));
Moritz Lipp's avatar
Moritz Lipp committed
208 209 210 211 212
  }

  g_string_free(string, TRUE);

  return false;
Moritz Lipp's avatar
Moritz Lipp committed
213 214
}

Sebastian Ramacher's avatar
Sebastian Ramacher committed
215
bool
216
cmd_help(girara_session_t* UNUSED(session), girara_list_t*
Moritz Lipp's avatar
Moritz Lipp committed
217
         UNUSED(argument_list))
Sebastian Ramacher's avatar
Sebastian Ramacher committed
218 219 220 221
{
  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
222 223 224 225 226 227 228 229 230 231 232 233 234 235
bool
cmd_hlsearch(girara_session_t* session, girara_list_t* UNUSED(argument_list))
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

  document_draw_search_results(zathura, true);
  render_all(zathura);

  return true;
}


236 237 238
bool
cmd_open(girara_session_t* session, girara_list_t* argument_list)
{
Sebastian Ramacher's avatar
Sebastian Ramacher committed
239 240 241 242 243 244
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

  const int argc = girara_list_size(argument_list);
  if (argc > 2) {
245
    girara_notify(session, GIRARA_ERROR, _("Too many arguments."));
Sebastian Ramacher's avatar
Sebastian Ramacher committed
246
    return false;
Moritz Lipp's avatar
Moritz Lipp committed
247
  } else if (argc >= 1) {
Moritz Lipp's avatar
Moritz Lipp committed
248 249
    if (zathura->document != NULL) {
      document_close(zathura, false);
250 251
    }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
252 253 254
    document_open_idle(zathura, girara_list_nth(argument_list, 0),
                       (argc == 2) ? girara_list_nth(argument_list, 1) : NULL,
                       ZATHURA_PAGE_NUMBER_UNSPECIFIED, NULL, NULL);
Moritz Lipp's avatar
Moritz Lipp committed
255
  } else {
256
    girara_notify(session, GIRARA_ERROR, _("No arguments given."));
Sebastian Ramacher's avatar
Sebastian Ramacher committed
257 258 259
    return false;
  }

260 261 262
  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
263 264 265 266 267 268 269 270
bool
cmd_quit(girara_session_t* session, girara_list_t* UNUSED(argument_list))
{
  sc_quit(session, NULL, NULL, 0);

  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
271
bool
272
cmd_print(girara_session_t* session, girara_list_t* UNUSED(argument_list))
Moritz Lipp's avatar
Moritz Lipp committed
273
{
274 275 276 277
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

Pavel Borzenkov's avatar
Pavel Borzenkov committed
278
  if (zathura->document == NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
279
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
Pavel Borzenkov's avatar
Pavel Borzenkov committed
280 281
    return false;
  }
282

Moritz Lipp's avatar
Moritz Lipp committed
283
  print(zathura);
284

Moritz Lipp's avatar
Moritz Lipp committed
285 286 287
  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
288 289 290
bool
cmd_nohlsearch(girara_session_t* session, girara_list_t* UNUSED(argument_list))
{
291
  sc_nohlsearch(session, NULL, NULL, 0);
Moritz Lipp's avatar
Moritz Lipp committed
292 293 294 295

  return true;
}

Moritz Lipp's avatar
Moritz Lipp committed
296
bool
Moritz Lipp's avatar
Moritz Lipp committed
297
cmd_save(girara_session_t* session, girara_list_t* argument_list)
Moritz Lipp's avatar
Moritz Lipp committed
298
{
299 300 301 302
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

Pavel Borzenkov's avatar
Pavel Borzenkov committed
303
  if (zathura->document == NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
304
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
Pavel Borzenkov's avatar
Pavel Borzenkov committed
305 306
    return false;
  }
307 308

  if (girara_list_size(argument_list) == 1) {
309
    if (document_save(zathura, girara_list_nth(argument_list, 0), false) == true) {
310
      girara_notify(session, GIRARA_INFO, _("Document saved."));
311
    } else {
312
      girara_notify(session, GIRARA_INFO, _("Failed to save document."));
313
    }
Moritz Lipp's avatar
Moritz Lipp committed
314
  } else {
315
    girara_notify(session, GIRARA_ERROR, _("Invalid number of arguments."));
316 317 318 319 320 321 322 323 324 325 326 327 328
    return false;
  }

  return true;
}

bool
cmd_savef(girara_session_t* session, girara_list_t* argument_list)
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

Pavel Borzenkov's avatar
Pavel Borzenkov committed
329
  if (zathura->document == NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
330
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
331
    return false;
Pavel Borzenkov's avatar
Pavel Borzenkov committed
332
  }
333 334

  if (girara_list_size(argument_list) == 1) {
335
    if (document_save(zathura, girara_list_nth(argument_list, 0), true) == true) {
336
      girara_notify(session, GIRARA_INFO, _("Document saved."));
337
    } else {
338
      girara_notify(session, GIRARA_INFO, _("Failed to save document."));
339
    }
Moritz Lipp's avatar
Moritz Lipp committed
340
  } else {
341
    girara_notify(session, GIRARA_ERROR, _("Invalid number of arguments."));
342 343 344
    return false;
  }

Moritz Lipp's avatar
Moritz Lipp committed
345 346
  return true;
}
Moritz Lipp's avatar
Moritz Lipp committed
347 348

bool
Sebastian Ramacher's avatar
Sebastian Ramacher committed
349
cmd_search(girara_session_t* session, const char* input, girara_argument_t* argument)
Moritz Lipp's avatar
Moritz Lipp committed
350 351 352 353 354 355 356
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(input != NULL, false);
  g_return_val_if_fail(argument != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

Sebastian Ramacher's avatar
Sebastian Ramacher committed
357
  if (zathura->document == NULL || strlen(input) == 0) {
Moritz Lipp's avatar
Moritz Lipp committed
358 359 360
    return false;
  }

361
  zathura_error_t error = ZATHURA_ERROR_OK;
362

363 364
  /* set search direction */
  zathura->global.search_direction = argument->n;
365 366 367 368

  unsigned int number_of_pages     = zathura_document_get_number_of_pages(zathura->document);
  unsigned int current_page_number = zathura_document_get_current_page_number(zathura->document);

Moritz Lipp's avatar
Moritz Lipp committed
369 370 371 372 373
  /* reset search highlighting */
  bool nohlsearch = false;
  girara_setting_get(session, "nohlsearch", &nohlsearch);

  /* search pages */
374
  for (unsigned int page_id = 0; page_id < number_of_pages; ++page_id) {
375
    unsigned int index = (page_id + current_page_number) % number_of_pages;
376
    zathura_page_t* page = zathura_document_get_page(zathura->document, index);
377
    if (page == NULL) {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
378 379 380
      continue;
    }

381
    GtkWidget* page_widget = zathura_page_get_widget(zathura, page);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
382 383
    GObject* obj_page_widget = G_OBJECT(page_widget);
    g_object_set(obj_page_widget, "draw-links", FALSE, NULL);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
384

385
    zathura_renderer_lock(zathura->sync.render_thread);
386
    girara_list_t* result = zathura_page_search_text(page, input, &error);
387
    zathura_renderer_unlock(zathura->sync.render_thread);
388

Sebastian Ramacher's avatar
Sebastian Ramacher committed
389 390
    if (result == NULL || girara_list_size(result) == 0) {
      girara_list_free(result);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
391
      g_object_set(obj_page_widget, "search-results", NULL, NULL);
392

393
      if (error == ZATHURA_ERROR_NOT_IMPLEMENTED) {
394 395 396 397
        break;
      } else {
        continue;
      }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
398 399
    }

Sebastian Ramacher's avatar
Sebastian Ramacher committed
400
    g_object_set(obj_page_widget, "search-results", result, NULL);
401 402 403

    if (argument->n == BACKWARD) {
      /* start at bottom hit in page */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
404
      g_object_set(obj_page_widget, "search-current", girara_list_size(result) - 1, NULL);
405
    } else {
Sebastian Ramacher's avatar
Sebastian Ramacher committed
406
      g_object_set(obj_page_widget, "search-current", 0, NULL);
407
    }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
408 409
  }

410 411 412 413
  girara_argument_t* arg = g_try_malloc0(sizeof(girara_argument_t));
  if (arg == NULL) {
    return false;
  }
414 415

  arg->n = FORWARD;
416
  arg->data = (void*) input;
417 418 419
  sc_search(session, arg, NULL, 0);
  g_free(arg);

Moritz Lipp's avatar
Moritz Lipp committed
420 421
  return true;
}
Sebastian Ramacher's avatar
Sebastian Ramacher committed
422 423 424 425 426 427 428 429

bool
cmd_export(girara_session_t* session, girara_list_t* argument_list)
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  if (zathura->document == NULL) {
430
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
Sebastian Ramacher's avatar
Sebastian Ramacher committed
431 432 433
    return false;
  }

434
  if (girara_list_size(argument_list) != 2) {
435
    girara_notify(session, GIRARA_ERROR, _("Invalid number of arguments given."));
Sebastian Ramacher's avatar
Sebastian Ramacher committed
436 437 438
    return false;
  }

Moritz Lipp's avatar
Moritz Lipp committed
439
  const char* file_identifier = girara_list_nth(argument_list, 0);
440 441
  const char* file_name       = girara_list_nth(argument_list, 1);

Moritz Lipp's avatar
Moritz Lipp committed
442
  if (file_name == NULL || file_identifier == NULL) {
443 444 445
    return false;
  }

Moritz Lipp's avatar
Moritz Lipp committed
446 447 448 449 450 451 452 453 454 455 456 457
  char* export_path = girara_fix_path(file_name);
  if (export_path == NULL) {
    return false;
  }

  /* attachment */
  if (strncmp(file_identifier, "attachment-", strlen("attachment-")) == 0) {
    if (zathura_document_attachment_save(zathura->document, file_identifier + strlen("attachment-"), export_path) == false) {
      girara_notify(session, GIRARA_ERROR, _("Couldn't write attachment '%s' to '%s'."), file_identifier, file_name);
    } else {
      girara_notify(session, GIRARA_INFO, _("Wrote attachment '%s' to '%s'."), file_identifier, export_path);
    }
Moritz Lipp's avatar
Moritz Lipp committed
458
    /* image */
Moritz Lipp's avatar
Moritz Lipp committed
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
  } else if (strncmp(file_identifier, "image-p", strlen("image-p")) == 0 && strlen(file_identifier) >= 10) {
    /* parse page id */
    const char* input = file_identifier + strlen("image-p");
    int page_id = atoi(input);
    if (page_id == 0) {
      goto image_error;
    }

    /* parse image id */
    input = strstr(input, "-");
    if (input == NULL) {
      goto image_error;
    }

    int image_id = atoi(input + 1);
    if (image_id == 0) {
      goto image_error;
    }

    /* get image */
    zathura_page_t* page = zathura_document_get_page(zathura->document, page_id - 1);
    if (page == NULL) {
      goto image_error;
    }

    girara_list_t* images = zathura_page_images_get(page, NULL);
    if (images == NULL) {
      goto image_error;
    }

    zathura_image_t* image = girara_list_nth(images, image_id - 1);
    if (image == NULL) {
      goto image_error;
    }

    cairo_surface_t* surface = zathura_page_image_get_cairo(page, image, NULL);
    if (surface == NULL) {
      goto image_error;
    }

    if (cairo_surface_write_to_png(surface, export_path) == CAIRO_STATUS_SUCCESS) {
      girara_notify(session, GIRARA_INFO, _("Wrote image '%s' to '%s'."), file_identifier, export_path);
    } else {
      girara_notify(session, GIRARA_ERROR, _("Couldn't write image '%s' to '%s'."), file_identifier, file_name);
    }

    goto error_ret;

image_error:

    girara_notify(session, GIRARA_ERROR, _("Unknown image '%s'."), file_identifier);
    goto error_ret;
Moritz Lipp's avatar
Moritz Lipp committed
511
    /* unknown */
Sebastian Ramacher's avatar
Sebastian Ramacher committed
512
  } else {
Moritz Lipp's avatar
Moritz Lipp committed
513
    girara_notify(session, GIRARA_ERROR, _("Unknown attachment or image '%s'."), file_identifier);
Sebastian Ramacher's avatar
Sebastian Ramacher committed
514 515
  }

Moritz Lipp's avatar
Moritz Lipp committed
516 517 518
error_ret:

  g_free(export_path);
519

Sebastian Ramacher's avatar
Sebastian Ramacher committed
520 521
  return true;
}
522

Moritz Lipp's avatar
Moritz Lipp committed
523 524 525 526 527 528 529 530 531 532
bool
cmd_exec(girara_session_t* session, girara_list_t* argument_list)
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

  if (zathura->document != NULL) {
    const char* path = zathura_document_get_path(zathura->document);

Sebastian Ramacher's avatar
Sebastian Ramacher committed
533
    GIRARA_LIST_FOREACH_BODY_WITH_ITER(argument_list, char*, iter, value,
Sebastian Ramacher's avatar
Sebastian Ramacher committed
534 535 536 537 538 539 540 541 542 543
      char* r = girara_replace_substring(value, "$FILE", path);

      if (r != NULL) {
        char* s = girara_replace_substring(r, "%", path);
        g_free(r);

        if (s != NULL) {
          girara_list_iterator_set(iter, s);
        }
      }
Sebastian Ramacher's avatar
Sebastian Ramacher committed
544
    );
Moritz Lipp's avatar
Moritz Lipp committed
545 546 547 548 549
  }

  return girara_exec_with_argument_list(session, argument_list);
}

550 551 552 553 554 555 556 557 558 559 560 561
bool
cmd_offset(girara_session_t* session, girara_list_t* argument_list)
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;
  if (zathura->document == NULL) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

  /* no argument: take current page as offset */
Moritz Lipp's avatar
Moritz Lipp committed
562
  int page_offset = zathura_document_get_current_page_number(zathura->document);
563 564 565 566 567 568 569 570 571 572 573 574 575

  /* retrieve offset from argument */
  if (girara_list_size(argument_list) == 1) {
    const char* value = girara_list_nth(argument_list, 0);
    if (value != NULL) {
      page_offset = atoi(value);
      if (page_offset == 0 && strcmp(value, "0") != 0) {
        girara_notify(session, GIRARA_WARNING, _("Argument must be a number."));
        return false;
      }
    }
  }

Moritz Lipp's avatar
Moritz Lipp committed
576
  zathura_document_set_page_offset(zathura->document, page_offset);
577 578 579

  return true;
}
Moritz Lipp's avatar
Moritz Lipp committed
580 581 582 583 584 585 586 587

bool
cmd_version(girara_session_t* session, girara_list_t* UNUSED(argument_list))
{
  g_return_val_if_fail(session != NULL, false);
  g_return_val_if_fail(session->global.data != NULL, false);
  zathura_t* zathura = session->global.data;

588
  char* string = zathura_get_version_string(zathura, true);
Moritz Lipp's avatar
Moritz Lipp committed
589 590 591
  if (string == NULL) {
    return false;
  }
Moritz Lipp's avatar
Moritz Lipp committed
592 593

  /* display information */
594
  girara_notify(session, GIRARA_INFO, "%s", string);
Moritz Lipp's avatar
Moritz Lipp committed
595

596
  g_free(string);
Moritz Lipp's avatar
Moritz Lipp committed
597 598 599

  return true;
}