private void replaceAction(
      String defaultString, int defaultOffsetCaret, String beforeString, String afterString) {
    if (SourceText.getSelectedText().isEmpty()) {
      SourceText.replaceText(SourceText.getSelection(), defaultString);
      SourceText.moveTo(SourceText.getCaretPosition() - defaultOffsetCaret);
    } else {
      SourceText.replaceText(
          SourceText.getSelection(), beforeString + SourceText.getSelectedText() + afterString);
    }

    SourceText.requestFocus();
  }
  @FXML
  private void HandleBlocButtonAction(ActionEvent event) {
    String text = "";
    String[] lines = SourceText.getSelectedText().split("\n");
    for (String line : lines) {
      text += "| " + line + "\n";
    }

    List<String> choices = new ArrayList<>();
    choices.add("information");
    choices.add("question");
    choices.add("attention");
    choices.add("erreur");

    ChoiceDialog<String> dialog = new ChoiceDialog<>("information", choices);
    dialog.setTitle("Choix du bloc");
    dialog.setHeaderText("Votre type de bloc");
    dialog.setContentText("Type de bloc: ");

    // Traditional way to get the response value.
    Optional<String> result = dialog.showAndWait();
    if (result.isPresent()) {
      SourceText.replaceText(SourceText.getSelection(), "\n[[" + result.get() + "]]\n" + text);
    }

    SourceText.requestFocus();
  }
  @FXML
  private void HandleBulletButtonAction(ActionEvent event) {
    if (SourceText.getSelectedText().isEmpty()) {
      SourceText.replaceText(SourceText.getSelection(), "- ");
    } else {
      StringBuilder sb = new StringBuilder();
      String[] lines = SourceText.getSelectedText().split("\n");
      for (String line : lines) {
        sb.append("- ").append(line).append("\n");
      }

      SourceText.replaceText(SourceText.getSelection(), sb.toString());
    }

    SourceText.requestFocus();
  }
  @FXML
  private void HandleLinkButtonAction(ActionEvent event) {
    String link = SourceText.getSelectedText();

    // Create the custom dialog.
    Dialog<Pair<String, String>> dialog = new Dialog<>();
    dialog.setTitle("Détail du lien");
    dialog.setHeaderText("");

    // Set the icon (must be included in the project).
    dialog.setGraphic(
        new ImageView(MainApp.class.getResource("assets/static/icons/link.png").toString()));

    dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);

    // Create the username and password labels and fields.
    GridPane grid = new GridPane();
    grid.setHgap(10);
    grid.setVgap(10);
    grid.setPadding(new Insets(20, 150, 10, 10));

    TextField tLink = new TextField();
    tLink.setText(link);
    TextField tLabel = new TextField();
    tLabel.setText(link);

    grid.add(new Label("Lien:"), 0, 0);
    grid.add(tLink, 1, 0);
    grid.add(new Label("Titre du lien"), 0, 1);
    grid.add(tLabel, 1, 1);

    dialog.getDialogPane().setContent(grid);

    // Request focus on the username field by default.
    Platform.runLater(tLink::requestFocus);

    // Convert the result to a username-password-pair when the login button
    // is clicked.
    dialog.setResultConverter(
        dialogButton -> {
          if (dialogButton == ButtonType.OK) {
            return new Pair<>(tLink.getText(), tLabel.getText());
          }
          return null;
        });

    Optional<Pair<String, String>> result = dialog.showAndWait();

    result.ifPresent(
        tLinkTLabel ->
            SourceText.replaceText(
                SourceText.getSelection(),
                "[" + tLinkTLabel.getValue() + "](" + tLinkTLabel.getKey() + ")"));

    SourceText.requestFocus();
  }
  @FXML
  private void HandleTableButtonAction(ActionEvent event) throws IOException {
    // Create the custom dialog.
    Dialog<Pair<ObservableList, ObservableList<ZRow>>> dialog = new Dialog<>();
    dialog.setTitle("Editeur de tableau");
    dialog.setHeaderText("");

    // Set the icon (must be included in the project).
    dialog.setGraphic(
        new ImageView(MainApp.class.getResource("assets/static/icons/table.png").toString()));

    // Set the button types.
    dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);

    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(MainApp.class.getResource("fxml/TableEditor.fxml"));
    BorderPane tableEditor = loader.load();
    TableView<ZRow> tbView = (TableView) tableEditor.getCenter();

    TableController controller = loader.getController();
    controller.setEditor(this);

    dialog.getDialogPane().setContent(tableEditor);

    dialog.setResultConverter(
        dialogButton -> {
          if (dialogButton == ButtonType.OK) {
            return new Pair<>(tbView.getColumns(), tbView.getItems());
          }
          return null;
        });

    Optional<Pair<ObservableList, ObservableList<ZRow>>> result = dialog.showAndWait();

    result.ifPresent(
        datas -> {
          String[][] data =
              new String[datas.getValue().size()][datas.getValue().get(0).getRow().size()];
          String[] headers = new String[datas.getKey().size()];
          int cpt = 0;
          for (Object key : datas.getKey()) {
            headers[cpt] = ((TextField) ((TableColumn) key).getGraphic()).getText();
            cpt++;
          }

          for (int i = 0; i < datas.getValue().size(); i++) {
            for (int j = 0; j < datas.getValue().get(i).getRow().size(); j++) {
              data[i][j] = datas.getValue().get(i).getRow().get(j);
            }
          }
          String tablestring = FlipTable.of(headers, data);
          SourceText.replaceText(SourceText.getSelection(), "\n\n" + tablestring + "\n\n");
          SourceText.requestFocus();
        });
  }
 @FXML
 private void HandleUnbreakableAction(ActionEvent event) {
   SourceText.replaceText(SourceText.getSelection(), SourceText.getSelectedText() + "\u00a0");
   SourceText.requestFocus();
 }
  @FXML
  private void HandleCodeButtonAction(ActionEvent event) {
    String code = SourceText.getSelectedText();
    if (code.trim().startsWith("```") && code.trim().endsWith("```")) {
      int start = code.trim().indexOf('\n') + 1;
      int end = code.trim().lastIndexOf('\n');
      code = code.substring(start, end);
    }

    // Create the custom dialog.
    Dialog<Pair<String, String>> dialog = new Dialog<>();
    dialog.setTitle("Editeur de code");
    dialog.setHeaderText("");

    // Set the icon (must be included in the project).
    dialog.setGraphic(
        new ImageView(MainApp.class.getResource("assets/static/icons/code.png").toString()));

    // Set the button types.
    dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);

    // Create the username and password labels and fields.
    GridPane grid = new GridPane();
    grid.setHgap(10);
    grid.setVgap(10);
    grid.setPadding(new Insets(20, 150, 10, 10));

    TextField tLangage = new TextField();
    TextArea tCode = new TextArea();
    tCode.setText(code);

    grid.add(new Label("Langage:"), 0, 0);
    grid.add(tLangage, 1, 0);
    grid.add(new Label("Code"), 0, 1);
    grid.add(tCode, 1, 1);

    dialog.getDialogPane().setContent(grid);

    // Request focus on the username field by default.
    Platform.runLater(tLangage::requestFocus);

    // Convert the result to a username-password-pair when the login button
    // is clicked.
    dialog.setResultConverter(
        dialogButton -> {
          if (dialogButton == ButtonType.OK) {
            return new Pair<>(tLangage.getText(), tCode.getText());
          }
          return null;
        });

    Optional<Pair<String, String>> result = dialog.showAndWait();

    result.ifPresent(
        tLangageTCode ->
            SourceText.replaceText(
                SourceText.getSelection(),
                "\n```" + tLangageTCode.getKey() + "\n" + tLangageTCode.getValue() + "\n```\n"));

    SourceText.requestFocus();
  }
 @FXML
 private void HandleHeaderButtonAction(ActionEvent event) {
   SourceText.replaceText(SourceText.getSelection(), "# " + SourceText.getSelectedText());
   SourceText.requestFocus();
 }