Open Libreoffice Writer to the Last Edited Document

More people should be using LibreOffice. Why? Because word processing is a mature technology, as mature as the doorknob, and there is no reason to keep paying tech companies like Microsoft increasingly exorbitant protection money as if we needed or wanted them to “improve” it–all the while making it easier for them to spy on us and sell us crap we don’t want. Capitalism is a powerful driver of progress, but sometimes that progress is, as C.S. Lewis put it, called “going bad.”

This isn’t 1988. Word processing doesn’t need anything but bug fixes and refinement between now and whenever the next revolution in AI or human biology renders the whole idea moot, and well-supported open-source software is safer than commercial software specifically because it’s open. More eyes are looking at the code with more detachment. It’s also a bit like a good Credit Union, driven by the needs of the community rather than the profits of a few oligarchs. So stop paying that monthly subscription and download LibreOffice for free. Go. We’ll wait.

But when you do, you’ll naturally find there’s a learning curve. That’s where I can help. I’m starting a series to share what I’ve learned as I’ve made the transition over the last decade or so.

In this post, the Libreoffice Macro facility and how to easily use it to do something super useful with no difficulty at all: Make Libreoffice Write open the last document you edited to the last spot you were at when you closed it.

These instructions are for LibreOffice Writer, V but should remain valid for a good long while unless someone at The Document Foundation gets the bad idea to emulate some even worse idea from Microsoft.

1. Click Tools – Macros – Edit Macros

This will open Libreoffice’s integrated macro development environment, functionally similar to the one for Visual Basic in Microsoft Office except this one supports dialects of the BASIC, Javascript, and Python languages. If you aren’t a computer programmer, this editor may seem daunting, but it needn’t be. It’s really just a text editor with autocomplete and formatting support for code and a debugger. Today tou don’t need to write or debug any code, or do anything more complex than cut & paste. Just follow some simple directions.

2. To the left, you’ll see a navigator with “My Macros – Standard – Module1” pretty much just like you would in MS Word. To the right, you’ll see a couple of lines of default code (if you’ve never been here before) for the “Main” subroutine (which is just a placeholder). That’s cool. Subroutines are just little programs, and in this environment, they are little programs that can interact with and be called by Libreoffice.

3. At the bottom of the right pane (code editor) paste in the following subroutines which will be used to handle recent file opening and configure Libreoffice to use them:

Sub set_Start_Application_Event_To_Open_Most_Recent_Document()
REM Programmatically connect the "Start Application" event to the Basic method called: Open_Most_Recent_Document().
REM Make sure that the Basic method called "Open_Most_Recent_Document" exists inside [My Macros & Dialogs],
REM inside the library called "Standard", inside the module called "LibreOffice".
REM Then call this method once to connect the event.
REM This causes the Most Recently opened Document to be opened *EVERY TIME* that the LO application starts up.

	set_Application_Event( "OnStartApp", "Standard", "Module1", "Open_Most_Recent_Document" ) 
End Sub

Sub set_Application_Event( sEventName as String, sLibrary As String, sModule As String, sFunction As String )
REM Connects the specified Application Event to the specified Basic macro.
REM <sEventName>: The Name of the Application Event to connect a macro to.
REM <sLibrary>	: The Name of the Library that contains the module <sModule>.
REM <sModule>	: The Name of the Module that contains the method <sFunction>.
REM <sFunction>	: The Name of the Method to be connected to the specified Application Event.

	Dim aProps(1) As New
	aProps(0).Name		= "EventType"
	aProps(0).Value		= "Script"
	aProps(1).Name		= "Script"
	aProps(1).Value		= "" & sLibrary & "." & sModule & "." & sFunction & "?language=Basic&location=application"
	Dim oGlobalEventBroadcaster As Object
	oGlobalEventBroadcaster = GetDefaultContext().getByName( "/singletons/" )
	oGlobalEventBroadcaster.Events.replaceByName( sEventName, aProps() )
	msgbox sEventName & " connected to: " & oGlobalEventBroadcaster.Events.getByName( sEventName )(1).Value, 64, "Set Application Event"
End Sub

Function Open_Most_Recent_Document()
REM Opens the Most Recently opened LibreOffice Document, and returns it if succesful.
	On Local Error Resume Next
	Open_Most_Recent_Document = StarDesktop.loadComponentFromURL( getMostRecentDocument(), "_blank", 0, Array() )
End Function

Function getMostRecentDocument() As String
REM Returns the URL of the most recently opened document in LibreOffice.
REM Returns an empty string if there are no recent documents.
	Dim aRecentDocs() As String
	aRecentDocs = getRecentDocuments()
	If uBound( aRecentDocs ) >= 0 Then getMostRecentDocument = aRecentDocs( 0 )
End Function

Function getRecentDocuments( Optional bOrdered As Boolean ) As Variant
REM	Returns an Array containing the URLs of LibreOffice Most Recent Documents.
REM <bOrdered>	: Pass <True> ( or leave empty ) to get the array sorted by most recent date;
REM				  Pass <False> to get the unordered List of Recent Documents.
	Dim aProps(1) As New
	aProps(0).Name	= "nodepath"
	aProps(0).Value	= "/org.openoffice.Office.Histories/Histories/"
	aProps(1).Name	= "enableasync"
	aProps(1).Value	= False
	Dim oConfig As Object, oHistory As Object
	oConfig		= createUnoService( "" )
	oHistory	= oConfig.createInstanceWithArguments( "", aProps() )

	If IsMissing( bOrdered ) Or bOrdered Then		  REM Create ordered item list:
		Dim oOrderList		As Object	:	oOrderList	= oHistory.PickList.OrderList
		Dim sOrderNames()	As String	:	sOrderNames	= oOrderList.getElementNames()
		Dim iMaxIndex		As Integer	:	iMaxIndex	= uBound( sOrderNames )
		Dim aOrderedList( iMaxIndex ) As String
		Dim i As Integer
		For i = 0 To iMaxIndex
			aOrderedList( i ) = oOrderList.getByName( sOrderNames(i) ).HistoryItemRef
		getRecentDocuments = aOrderedList()
		getRecentDocuments = oHistory.PickList.ItemList.getElementNames()
	End If
End Function

Sub RestoreLastView
REM Shift-F5 functionality ---------------------------
   dim document   as object
   dim dispatcher as object

   document   = ThisComponent.CurrentController.Frame
   dispatcher = createUnoService("")
   dispatcher.executeDispatch(document, ".uno:RestoreEditingView", "", 0, Array())
End sub

4. Got all that? Well you don’t have to. But here’s the cool thing about open source and community code: even if you aren’t expert enough to write it, you can still read it. Look it over. See anything nefarious? No? It’s actually pretty simple when it’s laid out in front of you. Rest easy.

5. Close the code editor (the code will be saved on your local machine) and back in Libreoffice Write, click Tools > Macros > Run Macro, then navigate to My Macros / Standard / Module1 (or wherever you pasted the code). Select “set_Start_Application_Event_To_Open_Most_Recent_Document” to the right and click “Run.”

Now to see what you just did, in Libreoffice Writer, click Tools > Customize and when the dialog box opens, click the “Events” tab. If the “Save in” selection at the bottom is not pointing to “LibreOffice,” change it to “Libreoffice.” Look to the right of the “Start Application” event (at the top of the dialog), and you’ll see it’s now set to call the “Open_Most_Recent_Document” macro in your Standard.Module1 library. If you ever want to turn this new feature off, just come back here and remove it. But for now, just close the dialog.

6. Now let’s try it out. Open any document in Writer. Close Writer. Open Writer. You should see the document you had open is open once again–and to the same place.

7. A little update. I don’t want to open the previous document when I’ve told Writer what to open by double-clicking a document in the file system, so I’ve made the following alteration.

  • First, I removed the Start Application event registered above by means of Tools/Customize/Start Application (with LibreOffice selected at the bottom rather than a particular file).
  • Second, I modified the properties of the start bar shortcut as follows: “C:\Program Files\LibreOffice\program\swriter.exe” “” To do this in Windows 11, you right-click on the shortcut, then right-click the “LibreOffice Writer” selection and choose “properties.”


Cool, huh? Now if you are adventurous, you might want to learn a little BASIC and write or modify your own macros. A great way to do this is in Libreoffice, as it has a fairly full-featured development environment that’s free and not too complex. And BASIC is a simple language. The hardest part is learning how to get your program to talk to Libreoffice, and poking around macros written by others (and Googling) is the best way to do that. You might, for example, modify this macro to open ALL previously opened files instead of just the most recent, or maybe to prompt you before doing so. Just keep a few things in mind:

  • Backups are your friend. Always save a known working copy before you start making changes, and that’s easy because it’s just text.
  • Organization is your friend. It’s easy to start small, build useful things over time, and end up with an unsupportable mess. Discipline yourself to keep order from the start. Give things clear names. Add comments (REM in Basic) to document your code. Keep backups and references organized too.
  • Beware reinventing the wheel. Before spending your time writing a macro, check to see if the functionality you want already exists. For example, Libreoffice already opens previously edited files to the last editing position so long as the author has been recorded in the file properties. I didn’t want to have to remember to do that, so I had a choice. I could either “reinvent the wheel” and add “restore editing view” to this macro, or write a new macro to auto-populate properties when I create a new file…or I can just start new projects from a template or copy of a preexisting file. There are lots of options aside from writing code.
  • The Macro Recorder is your friend: In my example above, I only needed to add the default “Shift-F5” functionality to my “open previous” macro and I’d be happy, but I had no idea how to do that. Fortunately, Libreoffice has a handy¬† feature for exactly this situation: record macro.
    • This feature must be enabled before use. Tools > Options > LibreOffice > Advanced and select the option “Enable macro recording”
    • Tools > Macros > Record Macro . A little “Record Macro” box appears on screen. (First attempt didn’t work, perhaps because feature is only available on document open and I’d had it open a while)
    • I shut down Writer (and its macro IDE) and tried again. As soon as my last document opened, I went to Tools > Macros > Record Macro. Then I paged down and clicked, pressed Shift-F5, saw the view change and paged down and clicked again, just to ensure some events were getting recorded.
    • I clicked “Stop Recording” and in the resulting dialog, prompted Libreoffice to create “Module2”
    • In Module2 I found the recorded code. As it happened, the paging down was not recorded but the “Restore last view call was” and I copied the contents of “Main” in Module2 into a new RestoreLastView Sub you see above and deleted Module2. I then called this new subroutine from the bottom of Open_Most_Recent_Document and Bob’s your uncle.

Like this? Interested in the series? Have questions or cool macro ideas of your own to share? Leave a comment and let me know!

See also: