Skip to content

Commit

Permalink
Implement auto-save backups that write a shadow document when editing…
Browse files Browse the repository at this point in the history
… text. If MM should crash next time you open MM it automatically opens both the original file and the backup file for editing.
  • Loading branch information
RickStrahl committed Dec 16, 2016
1 parent 7d8e1c5 commit 0904c9b
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 139 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Thumbs.db
*.tlb
*.tlh
*.bak
*.tmp
*.cache
*.ilk
*.log
Expand Down
10 changes: 8 additions & 2 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

# Markdown Monster Change Log

### Version 1.0.26
### Version 1.0.28
<i><small>not released yet</small></i>

* **Experimental Auto-Backup Implementation**
We've implemented Auto-Backup for now behind a `AutoSaveBackups` configuration flag that defaults to `false`. When set MM creates a `*.save.bak` file that shadows the actual edited file. The file is updated whenever text changes and acts as a live backup in a crash. When the original file is reopened in the editor MM notices the backup file and opens both files for comparison.

### Version 1.0.27
<i><small>December 13th, 2016</small></i>

* **Print Preview Html**
Expand Down Expand Up @@ -339,4 +345,4 @@ Updated the Dharkan and Blackout themes with slightly bigger fonts and wider lin
If updates can't be download the errors are no longer blowing up MM on exit. Also there's a pre-check now that checks for connection availability.

* **Image Embedding now prompts for local path**
When embedding a local image from a non-relative path you are now prompted if you want to copy the image to a local folder relative to the document.
When embedding a local image from a non-relative path you are now prompted if you want to copy the image to a local folder relative to the document.
260 changes: 144 additions & 116 deletions MarkdownMonster/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,30 @@ void SaveSettings()
config.Write();
}

public bool SaveFile()
{
var tab = TabControl.SelectedItem as TabItem;
if (tab == null)
return false;

var md = tab.Content;
var editor = tab.Tag as MarkdownDocumentEditor;
var doc = editor?.MarkdownDocument;
if (doc == null)
return false;

if (!editor.SaveDocument())
{
//var res = await this.ShowMessageOverlayAsync("Unable to save Document",
// "Unable to save document most likely due to missing permissions.");

MessageBox.Show("Unable to save document most likely due to missing permissions.", mmApp.ApplicationName);
return false;
}

return true;
}

#endregion

#region Tab Handling
Expand Down Expand Up @@ -487,7 +511,20 @@ public TabItem OpenTab(string mdFile = null,
if (doc.Filename != "untitled")
{
doc.Filename = mmFileUtils.GetPhysicalPath(doc.Filename);

if (doc.HasBackupFile())
{
ShowStatus("Auto-save recovery files have been found and opened in the editor.", milliSeconds: 9000);
SetStatusIcon(FontAwesomeIcon.Warning, Colors.Red);
{
File.Copy(doc.BackupFilename, doc.BackupFilename + ".md");
OpenTab(doc.BackupFilename + ".md");
File.Delete(doc.BackupFilename + ".md");
}
}



if (!doc.Load())
{
if (!batchOpen)
Expand Down Expand Up @@ -653,15 +690,17 @@ public bool CloseTab(TabItem tab, bool rebindTabHeaders = true)
if (!string.IsNullOrEmpty(doc.HtmlRenderFilename) && File.Exists(doc.HtmlRenderFilename))
File.Delete(doc.HtmlRenderFilename);

doc.CleanupBackupFile();

if (doc.IsDirty)
{

var res = MessageBox.Show(Path.GetFileName(doc.Filename) + "\r\n\r\nhas been modified.\r\n" +
"Do you want to save changes?",
"Save Document",
MessageBoxButton.YesNoCancel, MessageBoxImage.Question, MessageBoxResult.Cancel);
if (res == MessageBoxResult.Cancel)
{

return false; // don't close
}
if (res == MessageBoxResult.No)
Expand All @@ -676,7 +715,7 @@ public bool CloseTab(TabItem tab, bool rebindTabHeaders = true)
returnValue = false;
}
}

tab.Tag = null;
TabControl.Items.Remove(tab);

Expand Down Expand Up @@ -748,31 +787,6 @@ private void TabControlDragablz_TabItemClosing(ItemActionCallbackArgs<TabablzCon

#region Worker Functions

public bool SaveFile()
{
var tab = TabControl.SelectedItem as TabItem;
if (tab == null)
return false;

var md = tab.Content;
var editor = tab.Tag as MarkdownDocumentEditor;
var doc = editor?.MarkdownDocument;
if (doc == null)
return false;

if (!editor.SaveDocument())
{
//var res = await this.ShowMessageOverlayAsync("Unable to save Document",
// "Unable to save document most likely due to missing permissions.");

MessageBox.Show("Unable to save document most likely due to missing permissions.", mmApp.ApplicationName);
return false;
}

return true;
}


/// <summary>
/// Shows or hides the preview browser
/// </summary>
Expand Down Expand Up @@ -807,126 +821,137 @@ public void ShowPreviewBrowser(bool hide = false, bool refresh = false)
[HandleProcessCorruptedStateExceptions]
public void PreviewMarkdown(MarkdownDocumentEditor editor = null, bool keepScrollPosition = false, bool showInBrowser = false)
{
// only render if the preview is actually visible and rendering in Preview Browser
if (!Model.IsPreviewBrowserVisible && !showInBrowser)
return;
try
{
// only render if the preview is actually visible and rendering in Preview Browser
if (!Model.IsPreviewBrowserVisible && !showInBrowser)
return;

if (editor == null)
editor = GetActiveMarkdownEditor();
if (editor == null)
editor = GetActiveMarkdownEditor();

if (editor == null)
return;
if (editor == null)
return;

var doc = editor.MarkdownDocument;
var ext = Path.GetExtension(doc.Filename).ToLower().Replace(".","");
var doc = editor.MarkdownDocument;
var ext = Path.GetExtension(doc.Filename).ToLower().Replace(".", "");

string renderedHtml = null;
string renderedHtml = null;

if (string.IsNullOrEmpty(ext) || ext == "md" || ext == "html" || ext == "htm")
{
dynamic dom = null;
if (!showInBrowser)
if (string.IsNullOrEmpty(ext) || ext == "md" || ext == "html" || ext == "htm")
{
if (keepScrollPosition)
dynamic dom = null;
if (!showInBrowser)
{
dom = PreviewBrowser.Document;
editor.MarkdownDocument.LastBrowserScrollPosition = dom.documentElement.scrollTop;
if (keepScrollPosition)
{
dom = PreviewBrowser.Document;
editor.MarkdownDocument.LastBrowserScrollPosition = dom.documentElement.scrollTop;
}
else
{
ShowPreviewBrowser(false, false);
editor.MarkdownDocument.LastBrowserScrollPosition = 0;
}
}

if (ext == "html" || ext == "htm")
{
if (!editor.MarkdownDocument.WriteFile(editor.MarkdownDocument.HtmlRenderFilename,
editor.MarkdownDocument.CurrentText))
// need a way to clear browser window
return;
}
else
{
ShowPreviewBrowser(false, false);
editor.MarkdownDocument.LastBrowserScrollPosition = 0;
renderedHtml = editor.MarkdownDocument.RenderHtmlToFile(usePragmaLines: !showInBrowser &&
mmApp.Configuration
.PreviewSyncMode !=
PreviewSyncMode.None);
if (renderedHtml == null)
{
SetStatusIcon(FontAwesomeIcon.Warning, Colors.Red, false);
ShowStatus($"Access denied: {Path.GetFileName(editor.MarkdownDocument.Filename)}", 5000);
// need a way to clear browser window

return;
}
}
}

if (ext == "html" || ext == "htm")
{
if (!editor.MarkdownDocument.WriteFile(editor.MarkdownDocument.HtmlRenderFilename,
editor.MarkdownDocument.CurrentText))
// need a way to clear browser window
return;
}
else
{
renderedHtml = editor.MarkdownDocument.RenderHtmlToFile(usePragmaLines: !showInBrowser &&
mmApp.Configuration.PreviewSyncMode != PreviewSyncMode.None );
if (renderedHtml == null)
if (showInBrowser)
{
SetStatusIcon(FontAwesomeIcon.Warning, Colors.Red, false);
ShowStatus($"Access denied: {Path.GetFileName(editor.MarkdownDocument.Filename)}", 5000);
// need a way to clear browser window

ShellUtils.GoUrl(editor.MarkdownDocument.HtmlRenderFilename);
return;
}
}

if (showInBrowser)
{
ShellUtils.GoUrl(editor.MarkdownDocument.HtmlRenderFilename);
return;
}
else
{
PreviewBrowser.Cursor = Cursors.None;
PreviewBrowser.ForceCursor = true;
if (keepScrollPosition)
else
{
string browserUrl = PreviewBrowser.Source.ToString().ToLower();
string documentFile = "file:///" + editor.MarkdownDocument.HtmlRenderFilename.Replace('\\', '/').ToLower();
if (browserUrl == documentFile)
PreviewBrowser.Cursor = Cursors.None;
PreviewBrowser.ForceCursor = true;
if (keepScrollPosition)
{
dom = PreviewBrowser.Document;
//var content = dom.getElementById("MainContent");

string browserUrl = PreviewBrowser.Source.ToString().ToLower();
string documentFile = "file:///" +
editor.MarkdownDocument.HtmlRenderFilename.Replace('\\', '/')
.ToLower();
if (browserUrl == documentFile)
{
dom = PreviewBrowser.Document;
//var content = dom.getElementById("MainContent");

renderedHtml = StringUtils.ExtractString(renderedHtml,
"<!-- Markdown Monster Content -->",
"<!-- End Markdown Monster Content -->");

Debug.WriteLine("About to render HTML to browser...");
renderedHtml = StringUtils.ExtractString(renderedHtml,
"<!-- Markdown Monster Content -->",
"<!-- End Markdown Monster Content -->");

if (string.IsNullOrEmpty(renderedHtml))
PreviewMarkdown(editor, false, false); // fully reload document
else
{
try
if (string.IsNullOrEmpty(renderedHtml))
PreviewMarkdown(editor, false, false); // fully reload document
else
{
// explicitly update the document with JavaScript code
// much more efficient and non-jumpy and no wait cursor
var window = dom.parentWindow;
window.updateDocumentContent(renderedHtml);

try
{
// scroll preview to selected line
if (mmApp.Configuration.PreviewSyncMode == PreviewSyncMode.EditorAndPreview ||
mmApp.Configuration.PreviewSyncMode == PreviewSyncMode.EditorToPreview)
// explicitly update the document with JavaScript code
// much more efficient and non-jumpy and no wait cursor
var window = dom.parentWindow;
window.updateDocumentContent(renderedHtml);

try
{
int lineno = editor.GetLineNumber();
if (lineno > -1)
window.scrollToPragmaLine(lineno);
// scroll preview to selected line
if (mmApp.Configuration.PreviewSyncMode == PreviewSyncMode.EditorAndPreview ||
mmApp.Configuration.PreviewSyncMode == PreviewSyncMode.EditorToPreview)
{
int lineno = editor.GetLineNumber();
if (lineno > -1)
window.scrollToPragmaLine(lineno);
}
}
catch
{
/* ignore scroll error */
}
}
catch { /* ignore scroll error */ }
}
catch(Exception ex)
{
PreviewBrowser.Refresh(true);
catch (Exception ex)
{
PreviewBrowser.Refresh(true);
}

}

}
Debug.WriteLine("DONE to render HTML to browser...");

return;
return;
}
}
}

PreviewBrowser.Navigate(editor.MarkdownDocument.HtmlRenderFilename);
return;
PreviewBrowser.Navigate(editor.MarkdownDocument.HtmlRenderFilename);
return;
}
}
}

ShowPreviewBrowser(true,keepScrollPosition);
ShowPreviewBrowser(true, keepScrollPosition);
}
catch (Exception ex)
{
mmApp.Log("PreviewMarkdown failed (Exception captured - continuing)", ex);
}
}


Expand Down Expand Up @@ -1388,6 +1413,8 @@ private void HandleNamedPipe_OpenRequest(string filesToOpen)

#region StatusBar Display

private Timer statusTimer;

public void ShowStatus(string message = null, int milliSeconds = 0)
{
if (message == null)
Expand All @@ -1400,7 +1427,8 @@ public void ShowStatus(string message = null, int milliSeconds = 0)

if (milliSeconds > 0)
{
var t = new Timer((object win) =>
statusTimer?.Dispose();
statusTimer = new Timer((object win) =>
{
var window = win as MainWindow;
window.Dispatcher.Invoke(() => { window.ShowStatus(null, 0); } );
Expand Down
Loading

0 comments on commit 0904c9b

Please sign in to comment.