diff --git a/scribus/plugins/scriptplugin/cmddoc.cpp b/scribus/plugins/scriptplugin/cmddoc.cpp
index 258314045e..a3f1bfd810 100644
--- a/scribus/plugins/scriptplugin/cmddoc.cpp
+++ b/scribus/plugins/scriptplugin/cmddoc.cpp
@@ -470,6 +470,12 @@ PyObject* scribus_applymasterpage(PyObject* /* self */, PyObject* args)
 	Py_RETURN_NONE;
 }
 
+PyObject* scribus_updatedocument(PyObject* /* self */, PyObject* args)
+{
+  ScCore->primaryMainWindow()->updateDocument();
+  Py_RETURN_NONE;
+}
+
 /*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings
 with header files structure untouched (docstrings are kept near declarations)
 PV */
@@ -499,5 +505,6 @@ void cmddocdocwarnings()
 	  << scribus_setdoctype__doc__ 
 	  << scribus_setinfo__doc__
 	  << scribus_setmargins__doc__
-	  << scribus_setunit__doc__;
+	  << scribus_setunit__doc__
+	  << scribus_updatedocument__doc__;
 }
diff --git a/scribus/plugins/scriptplugin/cmddoc.h b/scribus/plugins/scriptplugin/cmddoc.h
index 110db951af..2625f0300c 100644
--- a/scribus/plugins/scriptplugin/cmddoc.h
+++ b/scribus/plugins/scriptplugin/cmddoc.h
@@ -313,6 +313,13 @@ Apply master page masterPageName on page pageNumber.\n\
 "));
 PyObject* scribus_applymasterpage(PyObject* self, PyObject* args);
 
+PyDoc_STRVAR(scribus_updatedocument__doc__,
+QT_TR_NOOP("updateDocument()\n\
+\n\
+Update the document.\n\
+"));
+PyObject* scribus_updatedocument(PyObject* self, PyObject* args);
+
 #endif
 
 
diff --git a/scribus/plugins/scriptplugin/cmdtext.cpp b/scribus/plugins/scriptplugin/cmdtext.cpp
index 6c3b6dcb9f..4597d2ab83 100644
--- a/scribus/plugins/scriptplugin/cmdtext.cpp
+++ b/scribus/plugins/scriptplugin/cmdtext.cpp
@@ -1402,6 +1402,119 @@ PyObject *scribus_ispdfbookmark(PyObject* /* self */, PyObject* args)
 	return PyBool_FromLong(0);
 }
 
+PyObject *scribus_getcharcoordinates(PyObject* /* self */, PyObject* args)
+{
+	int pos;
+	char *Name = const_cast<char*>("");
+	if (!PyArg_ParseTuple(args, "i|es", &pos, "utf-8", &Name))
+		return nullptr;
+	if (!checkHaveDocument())
+		return nullptr;
+	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
+	if (item == nullptr)
+		return nullptr;
+	if (!(item->isTextFrame()) && !(item->isPathText()))
+	{
+		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get character positions from a non-text frame.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	if ((pos < 0) || (pos >= static_cast<int>(item->itemText.length())))
+	{
+		PyErr_SetString(PyExc_IndexError, QObject::tr("Character index out of bounds.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	// When chaining the frame the char is in doesn't necessarily match
+	// the selected frame.
+	PageItem* actual = item->frameOfChar(pos);
+	if (actual == nullptr) {
+		PyErr_SetString(PyExc_IndexError, QObject::tr("Character index not visible in a frame.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	QLineF box = actual->textLayout.positionToPoint(pos);
+	// Can't use docUnitXToPageX and docUnitYToPageY because it might not
+	// be on the current page.
+	ScPage* actual_page
+	  = ScCore->primaryMainWindow()->doc->Pages->at(actual->OwnPage);
+	double page_x
+	  = PointToValue(actual->xPos() + box.x1() - actual_page->xOffset());
+	double page_y
+	  = PointToValue(actual->yPos() + box.y1() - actual_page->yOffset());
+
+	return Py_BuildValue("(idddd)",
+			     // Scripter API page starts at 1, not 0.
+			     actual->OwnPage + 1,
+			     page_x,
+			     page_y,
+			     PointToValue(box.x2() - box.x1()),
+			     PointToValue(box.y2() - box.y1()));
+}
+
+PyObject *scribus_getmark(PyObject* /* self */, PyObject* args)
+{
+	int pos;
+	char *Name = const_cast<char*>("");
+	if (!PyArg_ParseTuple(args, "i|es", &pos, "utf-8", &Name))
+		return nullptr;
+	if (!checkHaveDocument())
+		return nullptr;
+	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
+	if (item == nullptr)
+		return nullptr;
+	if (!(item->isTextFrame()) && !(item->isPathText()))
+	{
+		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot get mark info from a non-text frame.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	if ((pos < 0) || (pos >= static_cast<int>(item->itemText.length())))
+	{
+		PyErr_SetString(PyExc_IndexError, QObject::tr("Character index out of bounds.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	Mark* mark = item->itemText.mark(pos);
+	if (mark) {
+	  return Py_BuildValue(
+	      "{s:i,s:s,s:s}",
+	      "Type", mark->getType(),
+	      "Text", mark->getData().strtxt.toUtf8().data(),
+	      "Label", mark->label.toUtf8().data());
+	} else {
+	  Py_RETURN_NONE;
+	}
+}
+
+PyObject *scribus_setmarktext(PyObject* /* self */, PyObject* args)
+{
+	int pos;
+	char *val = const_cast<char*>("");
+	char *Name = const_cast<char*>("");
+	if (!PyArg_ParseTuple(args, "ies|es", &pos, "utf-8", &val,
+			      "utf-8", &Name))
+		return nullptr;
+	if (!checkHaveDocument())
+		return nullptr;
+	PageItem *item = GetUniqueItem(QString::fromUtf8(Name));
+	if (item == nullptr)
+		return nullptr;
+	if (!(item->isTextFrame()) && !(item->isPathText()))
+	{
+		PyErr_SetString(WrongFrameTypeError, QObject::tr("Cannot set mark text in a non-text frame.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	if ((pos < 0) || (pos >= static_cast<int>(item->itemText.length())))
+	{
+		PyErr_SetString(PyExc_IndexError, QObject::tr("Character index out of bounds.","python error").toLocal8Bit().constData());
+		return nullptr;
+	}
+	Mark* mark = item->itemText.mark(pos);
+	if (!mark) {
+	  PyErr_SetString(PyExc_ValueError, QObject::tr("No mark at that index.","python error").toLocal8Bit().constData());
+	  return nullptr;
+	}
+
+	mark->setString(QString::fromUtf8(val));
+	Py_RETURN_NONE;
+}
+
 /*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings
 with header files structure untouched (docstrings are kept near declarations)
 PV */
@@ -1418,6 +1531,7 @@ void cmdtextdocwarnings()
 	  << scribus_getfontsize__doc__
 	  << scribus_getframetext__doc__
 	  << scribus_getlinespace__doc__
+	  << scribus_getmark__doc__
 	  << scribus_gettext__doc__ // Deprecated
 	  << scribus_gettextcolor__doc__
 	  << scribus_gettextdistances__doc__
@@ -1434,6 +1548,7 @@ void cmdtextdocwarnings()
 	  << scribus_layouttextchain__doc__
 	  << scribus_linktextframes__doc__
 	  << scribus_outlinetext__doc__
+	  << scribus_getcharcoordinates__doc__
 	  << scribus_selectframetext__doc__
 	  << scribus_selecttext__doc__
 	  << scribus_setalign__doc__
@@ -1445,6 +1560,7 @@ void cmdtextdocwarnings()
 	  << scribus_setfontsize__doc__
 	  << scribus_setlinespace__doc__
 	  << scribus_setlinespacemode__doc__
+	  << scribus_setmarktext__doc__
 	  << scribus_setpdfbookmark__doc__
 	  << scribus_settextdistances__doc__
 	  << scribus_settext__doc__
diff --git a/scribus/plugins/scriptplugin/cmdtext.h b/scribus/plugins/scriptplugin/cmdtext.h
index 034aa126f5..7052dc0541 100644
--- a/scribus/plugins/scriptplugin/cmdtext.h
+++ b/scribus/plugins/scriptplugin/cmdtext.h
@@ -602,4 +602,41 @@ May raise WrongFrameTypeError if the target frame is not a text frame\n\
 /*! Is PDF bookmark? */
 PyObject *scribus_ispdfbookmark(PyObject * /*self*/, PyObject* args);
 
+/*! docstring */
+PyDoc_STRVAR(scribus_getcharcoordinates__doc__,
+QT_TR_NOOP("getCharCoordinates(pos, [\"name\"]) -> (page,x,y,width,height)\n\
+\n\
+Returns a (page, x, y, width, height) tuple based on the character at\n\
+position \"pos\" in the text frame \"name\". If the text frame is chained\n\
+from another text frame, \"pos\" is based on the overall story text. If\n\
+ \"name\" is not given the currently selected item is used.\n\
+\n\
+Will only work properly if the text has been layed out; you may need to call\n\
+layoutText() or layoutTextChain() first for correct results.\n\
+"));
+/*! Point for glyth at position */
+PyObject *scribus_getcharcoordinates(PyObject * /*self*/, PyObject* args);
+
+/*! docstring */
+PyDoc_STRVAR(scribus_getmark__doc__,
+QT_TR_NOOP("getMark(pos, [\"name\"]) -> (type,text)\n\
+\n\
+Returns a (type, text) tuple for the mark at position pos in object \"name\".\n\
+If \"name\" is not given the currently selected item is used. If there is no\n\
+mark at that position, type is -1.\n\
+"));
+/*! Returns info about mark */
+PyObject *scribus_getmark(PyObject * /*self*/, PyObject* args);
+
+/*! docstring */
+PyDoc_STRVAR(scribus_setmarktext__doc__,
+QT_TR_NOOP("setMarkText(pos, \"text\", [\"name\"])\n\
+\n\
+Returns a (type, text) tuple for the mark at position pos in object \"name\".\n\
+If \"name\" is not given the currently selected item is used. If there is no\n\
+mark at that position, type is -1.\n\
+"));
+/*! Returns info about mark */
+PyObject *scribus_setmarktext(PyObject * /*self*/, PyObject* args);
+
 #endif
diff --git a/scribus/plugins/scriptplugin/scriptplugin.cpp b/scribus/plugins/scriptplugin/scriptplugin.cpp
index aab82fa3b6..7b5ab29423 100644
--- a/scribus/plugins/scriptplugin/scriptplugin.cpp
+++ b/scribus/plugins/scriptplugin/scriptplugin.cpp
@@ -414,6 +414,8 @@ PyMethodDef scribus_methods[] = {
 	{const_cast<char*>("getUnit"), (PyCFunction)scribus_getunit, METH_NOARGS, tr(scribus_getunit__doc__)},
 	{const_cast<char*>("getVGuides"), (PyCFunction)scribus_getVguides, METH_NOARGS, tr(scribus_getVguides__doc__)},
 	{const_cast<char*>("getXFontNames"), (PyCFunction)scribus_xfontnames, METH_NOARGS, tr(scribus_xfontnames__doc__)},
+	{const_cast<char*>("getCharCoordinates"), scribus_getcharcoordinates, METH_VARARGS, tr(scribus_getcharcoordinates__doc__)},
+	{const_cast<char*>("getMark"), scribus_getmark, METH_VARARGS, tr(scribus_getmark__doc__)},
 	{const_cast<char*>("gotoPage"), scribus_gotopage, METH_VARARGS, tr(scribus_gotopage__doc__)},
 	{const_cast<char*>("groupObjects"), (PyCFunction)scribus_groupobj, METH_VARARGS, tr(scribus_groupobj__doc__)},
 	{const_cast<char*>("haveDoc"), (PyCFunction)scribus_havedoc, METH_NOARGS, tr(scribus_havedoc__doc__)},
@@ -431,6 +433,7 @@ PyMethodDef scribus_methods[] = {
 	{const_cast<char*>("isLocked"), scribus_islocked, METH_VARARGS, tr(scribus_islocked__doc__)},
 	{const_cast<char*>("layoutText"), scribus_layouttext, METH_VARARGS, tr(scribus_layouttext__doc__)},
 	{const_cast<char*>("layoutTextChain"), scribus_layouttextchain, METH_VARARGS, tr(scribus_layouttextchain__doc__)},
+	{const_cast<char*>("updateDocument"), scribus_updatedocument, METH_VARARGS, tr(scribus_updatedocument__doc__)},
 	{const_cast<char*>("linkTextFrames"), scribus_linktextframes, METH_VARARGS, tr(scribus_linktextframes__doc__)},
 	{const_cast<char*>("loadImage"), scribus_loadimage, METH_VARARGS, tr(scribus_loadimage__doc__)},
 	{const_cast<char*>("loadStylesFromFile"), scribus_loadstylesfromfile, METH_VARARGS, tr(scribus_loadstylesfromfile__doc__)},
@@ -538,6 +541,7 @@ PyMethodDef scribus_methods[] = {
 	{const_cast<char*>("setLineWidth"), scribus_setlinewidth, METH_VARARGS, tr(scribus_setlinewidth__doc__)},
 	{const_cast<char*>("setBleeds"), scribus_setbleeds, METH_VARARGS, tr(scribus_setbleeds__doc__)},
 	{const_cast<char*>("setMargins"), scribus_setmargins, METH_VARARGS, tr(scribus_setmargins__doc__)},
+	{const_cast<char*>("setMarkText"), scribus_setmarktext, METH_VARARGS, tr(scribus_setmarktext__doc__)},
 	{const_cast<char*>("setBaseLine"), scribus_setbaseline, METH_VARARGS, tr(scribus_setbaseline__doc__)},
 	{const_cast<char*>("setItemName"), scribus_setitemname, METH_VARARGS, tr(scribus_setitemname__doc__)},
 	{const_cast<char*>("setMultiLine"), scribus_setmultiline, METH_VARARGS, tr(scribus_setmultiline__doc__)},
