/* SPDX-License-Identifier: Zlib */

#include "commands.h"

#include <girara-gtk/commands.h>
#include <girara-gtk/session.h>
#include <girara-gtk/settings.h>
#include <girara/datastructures.h>
#include <girara/utils.h>
#include <girara/log.h>
#include <glib/gi18n.h>
#include <stdlib.h>
#include <string.h>

#include "adjustment.h"
#include "bookmarks.h"
#include "config.h"
#include "database.h"
#include "dbus-interface.h"
#include "document-widget.h"
#include "document.h"
#include "internal.h"
#include "page-widget.h"
#include "page.h"
#include "plugin.h"
#include "print.h"
#include "render.h"
#include "shortcuts.h"
#include "utils.h"
#include "zathura.h"

bool cmd_bookmark_create(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;
  zathura_document_t* document = zathura_get_document(zathura);
  if (document == NULL) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

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

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

  bookmark = zathura_bookmark_add(zathura, bookmark_name, zathura_document_get_current_page_number(document) + 1);
  if (bookmark == NULL) {
    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);
    }
    return false;
  } 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);
    }
  }

  return true;
}

bool cmd_bookmark_delete(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_has_document(zathura) == false) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

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

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

  return true;
}

bool cmd_bookmark_list(girara_session_t* session, girara_list_t* GIRARA_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;
  if (zathura_has_document(zathura) == false) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

  g_autoptr(GString) string = g_string_new(NULL);
  for (size_t idx = 0; idx != girara_list_size(zathura->bookmarks.bookmarks); ++idx) {
    zathura_bookmark_t* bookmark = girara_list_nth(zathura->bookmarks.bookmarks, idx);
    g_autofree gchar* escaped_id = g_markup_escape_text(bookmark->id, -1);
    g_string_append_printf(string, "<b>%s</b>: %u\n", escaped_id, bookmark->page);
  }

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

  return true;
}

bool cmd_bookmark_open(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_has_document(zathura) == false) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

  const unsigned int argc = girara_list_size(argument_list);
  if (argc != 1) {
    girara_notify(session, GIRARA_ERROR, _("Invalid number of arguments given."));
    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) {
    girara_notify(session, GIRARA_ERROR, _("No such bookmark: %s"), bookmark_name);
    return false;
  }

  zathura_jumplist_add(zathura);
  page_set(zathura, bookmark->page - 1);
  if (bookmark->x != DBL_MIN && bookmark->y != DBL_MIN) {
    position_set(zathura, bookmark->x, bookmark->y);
  }
  zathura_jumplist_add(zathura);

  return true;
}

bool cmd_jumplist_list(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_has_document(zathura) == false) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

  int num_entries = 5;

  const unsigned int argc = girara_list_size(argument_list);
  if (argc == 1) {
    int value = g_ascii_strtoll(girara_list_nth(argument_list, 0), NULL, 10);
    if (value == 0) {
      girara_notify(session, GIRARA_WARNING, _("Argument must be a nonzero number."));
      return false;
    } else if (value > 0) {
      num_entries = value;
    } else {
      num_entries = (int)zathura->jumplist.size + value;
    }
  } else if (argc != 0) {
    girara_notify(session, GIRARA_ERROR, _("Invalid number of arguments given."));
    return false;
  }

  if (num_entries <= 0) {
    return true;
  }

  zathura_jump_t* current_jump = zathura_jumplist_current(zathura);
  g_autoptr(GString) string    = g_string_new(NULL);
  for (int i = zathura->jumplist.size - 1; i >= 0 && num_entries > 0; --i, --num_entries) {
    const zathura_jump_t* j = girara_list_nth(zathura->jumplist.list, i);
    g_string_append_printf(string, _("[%d]: page=<b>%2d</b>, x=%f, y=%f %s\n"), i, j->page + 1, j->x, j->y,
                           j == current_jump ? _("(current)") : "");
  }

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

  return true;
}

bool cmd_close(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;
  if (zathura_has_document(zathura) == false) {
    return true;
  }

  document_close(zathura, false);

  return true;
}

bool cmd_info(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;
  if (zathura_has_document(zathura) == false) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

  struct meta_field {
    const char* name;
    zathura_document_information_type_t field;
  };

  const struct meta_field meta_fields[] = {
      {_("Title"), ZATHURA_DOCUMENT_INFORMATION_TITLE},
      {_("Subject"), ZATHURA_DOCUMENT_INFORMATION_SUBJECT},
      {_("Keywords"), ZATHURA_DOCUMENT_INFORMATION_KEYWORDS},
      {_("Author"), ZATHURA_DOCUMENT_INFORMATION_AUTHOR},
      {_("Creator"), ZATHURA_DOCUMENT_INFORMATION_CREATOR},
      {_("Producer"), ZATHURA_DOCUMENT_INFORMATION_PRODUCER},
      {_("Creation date"), ZATHURA_DOCUMENT_INFORMATION_CREATION_DATE},
      {_("Modification date"), ZATHURA_DOCUMENT_INFORMATION_MODIFICATION_DATE},
      {_("Format"), ZATHURA_DOCUMENT_INFORMATION_FORMAT},
      {_("Other"), ZATHURA_DOCUMENT_INFORMATION_OTHER},
  };

  girara_list_t* information = zathura_document_get_information(zathura_get_document(zathura), NULL);
  if (information == NULL) {
    girara_notify(session, GIRARA_INFO, _("No information available."));
    return false;
  }

  g_autoptr(GString) string = g_string_new(NULL);
  for (size_t i = 0; i < LENGTH(meta_fields); i++) {
    for (size_t idx = 0; idx != girara_list_size(information); ++idx) {
      zathura_document_information_entry_t* entry = girara_list_nth(information, idx);
      if (entry != NULL && meta_fields[i].field == entry->type) {
        g_autofree gchar* escaped_value = g_markup_escape_text(entry->value, -1);
        g_string_append_printf(string, "<b>%s:</b> %s\n", meta_fields[i].name, escaped_value);
      }
    }
  }

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

  return false;
}

bool cmd_help(girara_session_t* session, girara_list_t* UNUSED(argument_list)) {
  g_return_val_if_fail(session != NULL, false);
#if defined(WITH_MANPAGES) || defined(WITH_SANDBOX)
  girara_notify(session, GIRARA_INFO,
                _("Please check the man pages zathura(1) and zathurarc(5) for more information."));
#else
  girara_xdg_open("https://manpages.debian.org/unstable/zathura/zathura.1.en.html");
#endif

  return true;
}

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);
  zathura_document_widget_render_all(zathura->ui.document_widget);

  return true;
}

bool cmd_open(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;

  const int argc = girara_list_size(argument_list);
  if (argc > 2) {
    girara_notify(session, GIRARA_ERROR, _("Too many arguments."));
    return false;
  } else if (argc >= 1) {
    if (zathura_has_document(zathura) == true) {
      document_close(zathura, false);
    }

    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, NULL, NULL);
  } else {
    girara_notify(session, GIRARA_ERROR, _("No arguments given."));
    return false;
  }

  return true;
}

bool cmd_quit(girara_session_t* session, girara_list_t* UNUSED(argument_list)) {
  sc_quit(session, NULL, NULL, 0);

  return true;
}

bool cmd_print(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;

  if (zathura_has_document(zathura) == false) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

#ifdef WITH_SANDBOX
  girara_notify(zathura->ui.session, GIRARA_ERROR, _("Printing is not permitted in strict sandbox mode"));
  return false;
#else
  print(zathura);

  return true;
#endif
}

bool cmd_nohlsearch(girara_session_t* session, girara_list_t* UNUSED(argument_list)) {
  sc_nohlsearch(session, NULL, NULL, 0);

  return true;
}

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

#ifdef WITH_SANDBOX
  girara_notify(zathura->ui.session, GIRARA_ERROR, _("Saving is not permitted in strict sandbox mode"));
  return false;
#else
  if (zathura_has_document(zathura) == false) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

  if (girara_list_size(argument_list) == 1) {
    document_save(zathura, girara_list_nth(argument_list, 0), false);
  } else {
    girara_notify(session, GIRARA_ERROR, _("Invalid number of arguments."));
    return false;
  }

  return true;
#endif
}

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

#ifdef WITH_SANDBOX
  girara_notify(zathura->ui.session, GIRARA_ERROR, _("Saving is not permitted in strict sandbox mode"));
  return false;
#else
  if (zathura_has_document(zathura) == false) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

  if (girara_list_size(argument_list) == 1) {
    document_save(zathura, girara_list_nth(argument_list, 0), true);
  } else {
    girara_notify(session, GIRARA_ERROR, _("Invalid number of arguments."));
    return false;
  }

  return true;
#endif
}

bool cmd_search(girara_session_t* session, const char* input, girara_argument_t* argument) {
  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;
  zathura_document_t* document = zathura_get_document(zathura);

  if (document == NULL || strlen(input) == 0) {
    return false;
  }

  zathura_error_t error = ZATHURA_ERROR_OK;

  /* set search direction */
  zathura->global.search_direction = argument->n;

  unsigned int number_of_pages     = zathura_document_get_number_of_pages(document);
  unsigned int current_page_number = zathura_document_get_current_page_number(document);

  zathura->global.total_search_results  = 0;
  zathura->global.current_search_result = 0;

  /* reset search highlighting */
  bool nohlsearch = false;
  girara_setting_get(session, "nohlsearch", &nohlsearch);

  /* search pages */
  for (unsigned int page_id = 0; page_id < number_of_pages; ++page_id) {
    unsigned int index   = (page_id + current_page_number) % number_of_pages;
    zathura_page_t* page = zathura_document_get_page(document, index);
    if (page == NULL) {
      continue;
    }

    GtkWidget* page_widget   = zathura_page_get_widget(zathura, page);
    GObject* obj_page_widget = G_OBJECT(page_widget);
    g_object_set(obj_page_widget, "draw-links", FALSE, NULL);

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

    if (result == NULL || girara_list_size(result) == 0) {
      girara_list_free(result);
      g_object_set(obj_page_widget, "search-results", NULL, NULL);

      if (error == ZATHURA_ERROR_NOT_IMPLEMENTED) {
        break;
      } else {
        continue;
      }
    }

    g_object_set(obj_page_widget, "search-results", result, NULL);

    if (argument->n == BACKWARD) {
      /* start at bottom hit in page */
      g_object_set(obj_page_widget, "search-current", girara_list_size(result) - 1, NULL);
    } else {
      g_object_set(obj_page_widget, "search-current", 0, NULL);
    }

    zathura->global.total_search_results += girara_list_size(result);
  }

  g_autofree girara_argument_t* arg = g_try_malloc0(sizeof(girara_argument_t));
  if (arg == NULL) {
    return false;
  }

  bool inc_search = false;
  girara_setting_get(session, "incremental-search", &inc_search);

  arg->n    = FORWARD;
  arg->data = (void*)input;
  search_document(zathura, arg, inc_search);

  return true;
}

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

#ifdef WITH_SANDBOX
  girara_notify(zathura->ui.session, GIRARA_ERROR, _("Exporting attachments is not permitted in strict sandbox mode"));
  return false;
#else
  zathura_document_t* document = zathura_get_document(zathura);
  if (document == NULL) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

  if (girara_list_size(argument_list) != 2) {
    girara_notify(session, GIRARA_ERROR, _("Invalid number of arguments given."));
    return false;
  }

  const char* file_identifier = girara_list_nth(argument_list, 0);
  const char* file_name       = girara_list_nth(argument_list, 1);

  if (file_name == NULL || file_identifier == NULL) {
    return false;
  }

  g_autofree char* export_path = girara_fix_path(file_name);
  if (export_path == NULL) {
    return false;
  }

  static const size_t attachment_len = sizeof("attachment-") - 1;
  static const size_t image_len      = sizeof("image-p") - 1;

  /* attachment */
  if (strncmp(file_identifier, "attachment-", attachment_len) == 0) {
    if (zathura_document_attachment_save(document, file_identifier + attachment_len, export_path) != ZATHURA_ERROR_OK) {
      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);
    }
    /* image */
  } else if (strncmp(file_identifier, "image-p", image_len) == 0 && strlen(file_identifier) >= 10) {
    /* parse page id */
    const char* input    = file_identifier + image_len;
    char* input_image_id = NULL;
    guint64 page_id      = g_ascii_strtoull(input, &input_image_id, 10);
    if (page_id == 0 || page_id >= UINT_MAX || !input_image_id || input_image_id[0] != '-') {
      goto image_error;
    }

    /* parse image id */
    guint64 image_id = 0;
    if (!g_ascii_string_to_unsigned(input_image_id + 1, 10, 1, UINT_MAX, &image_id, NULL)) {
      goto image_error;
    }

    /* get image */
    zathura_page_t* page = zathura_document_get_page(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);
    }

    cairo_surface_destroy(surface);
    return true;

  image_error:
    girara_notify(session, GIRARA_ERROR, _("Unknown image '%s'."), file_identifier);
    return true;
    /* unknown */
  } else {
    girara_notify(session, GIRARA_ERROR, _("Unknown attachment or image '%s'."), file_identifier);
  }

  return true;
#endif
}

#ifndef WITH_SANDBOX
static bool exec_with_argument_list(girara_session_t* session, girara_list_t* argument_list) {
  g_autoptr(GStrvBuilder) builder = g_strv_builder_new();

  g_autofree char* cmd = NULL;
  girara_setting_get(session, "exec-command", &cmd);
  if (cmd && strlen(cmd)) {
    g_strv_builder_add(builder, cmd);
  } else {
    girara_debug("exec-command is empty, executing directly.");
  }

  for (size_t idx = 0; idx != girara_list_size(argument_list); ++idx) {
    g_strv_builder_add(builder, girara_list_nth(argument_list, idx));
  };

  g_auto(GStrv) argv      = g_strv_builder_end(builder);
  g_autoptr(GError) error = NULL;
  gboolean ret            = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
  if (!ret) {
    girara_warning("Failed to execute command: %s", error->message);
    girara_notify(session, GIRARA_ERROR, _("Failed to execute command: %s"), error->message);
  }

  return ret;
}
#endif

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

#ifdef WITH_SANDBOX
  girara_notify(zathura->ui.session, GIRARA_ERROR, _("Exec is not permitted in strict sandbox mode"));
  return false;
#else
  if (zathura->dbus != NULL) {
    const char* bus_name = zathura_dbus_get_name(zathura);
    for (size_t idx = 0; idx != girara_list_size(argument_list); ++idx) {
      char* value = girara_list_nth(argument_list, idx);
      char* s     = girara_replace_substring(value, "$DBUS", bus_name);
      if (s != NULL) {
        girara_list_set_nth(argument_list, idx, s);
      }
    }
  }

  zathura_document_t* document = zathura_get_document(zathura);
  if (document != NULL) {
    const char* path  = zathura_document_get_path(document);
    unsigned int page = zathura_document_get_current_page_number(document);
    char page_buf[G_ASCII_DTOSTR_BUF_SIZE];
    g_ascii_dtostr(page_buf, G_ASCII_DTOSTR_BUF_SIZE, page + 1);

    for (size_t idx = 0; idx != girara_list_size(argument_list); ++idx) {
      char* value        = girara_list_nth(argument_list, idx);
      g_autofree char* r = girara_replace_substring(value, "$PAGE", page_buf);
      if (r != NULL) {
        char* s = girara_replace_substring(r, "$FILE", path);
        if (s != NULL) {
          girara_list_set_nth(argument_list, idx, s);
        }
      }
    };
  }

  return exec_with_argument_list(session, argument_list);
#endif
}

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;
  zathura_document_t* document = zathura_get_document(zathura);
  if (document == NULL) {
    girara_notify(session, GIRARA_ERROR, _("No document opened."));
    return false;
  }

  /* no argument: take current page as offset */
  unsigned int page_offset = zathura_document_get_current_page_number(document);

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

  zathura_document_set_page_offset(document, page_offset);

  return true;
}

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;

  g_autofree char* string = zathura_get_version_string(zathura->plugins.manager, true);
  if (string == NULL) {
    return false;
  }

  /* display information */
  girara_notify(session, GIRARA_INFO, "%s", string);
  return true;
}

bool cmd_source(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;

  const int argc = girara_list_size(argument_list);
  if (argc > 1) {
    girara_notify(session, GIRARA_ERROR, _("Too many arguments."));
    return false;
  } else if (argc == 1) {
    zathura_set_config_dir(zathura, girara_list_nth(argument_list, 0));
  }
  config_load_files(zathura);

  return true;
}
