OSDN Git Service

Fix the problem that the BS key does not work at the beginning of the line after...
[winmerge-jp/winmerge-jp.git] / Src / MergeEditView.cpp
index 8dce338..b6fc755 100644 (file)
@@ -32,6 +32,7 @@
 #include "DirDoc.h"
 #include "ShellContextMenu.h"
 #include "editcmd.h"
+#include "Shell.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
@@ -63,11 +64,11 @@ CMergeEditView::CMergeEditView()
 , m_nThisGroup(0)
 , m_bDetailView(false)
 , m_piMergeEditStatus(nullptr)
-, m_bAutomaticRescan(false)
 , fTimerWaitingForIdle(0)
 , m_lineBegin(0)
 , m_lineEnd(-1)
 , m_CurrentPredifferID(0)
+, m_bChangedSchemeManually(false)
 {
        SetParser(&m_xParser);
        
@@ -137,12 +138,20 @@ BEGIN_MESSAGE_MAP(CMergeEditView, CCrystalEditViewEx)
        ON_UPDATE_COMMAND_UI(ID_AUTO_MERGE, OnUpdateAutoMerge)
        ON_COMMAND(ID_L2R, OnL2r)
        ON_UPDATE_COMMAND_UI(ID_L2R, OnUpdateL2r)
+       ON_COMMAND(ID_LINES_L2R, OnLinesL2r)
+       ON_UPDATE_COMMAND_UI(ID_LINES_L2R, OnUpdateLinesL2r)
        ON_COMMAND(ID_R2L, OnR2l)
        ON_UPDATE_COMMAND_UI(ID_R2L, OnUpdateR2l)
+       ON_COMMAND(ID_LINES_R2L, OnLinesR2l)
+       ON_UPDATE_COMMAND_UI(ID_LINES_R2L, OnUpdateLinesR2l)
        ON_COMMAND(ID_COPY_FROM_LEFT, OnCopyFromLeft)
        ON_UPDATE_COMMAND_UI(ID_COPY_FROM_LEFT, OnUpdateCopyFromLeft)
+       ON_COMMAND(ID_COPY_LINES_FROM_LEFT, OnCopyLinesFromLeft)
+       ON_UPDATE_COMMAND_UI(ID_COPY_LINES_FROM_LEFT, OnUpdateCopyLinesFromLeft)
        ON_COMMAND(ID_COPY_FROM_RIGHT, OnCopyFromRight)
        ON_UPDATE_COMMAND_UI(ID_COPY_FROM_RIGHT, OnUpdateCopyFromRight)
+       ON_COMMAND(ID_COPY_LINES_FROM_RIGHT, OnCopyLinesFromRight)
+       ON_UPDATE_COMMAND_UI(ID_COPY_LINES_FROM_RIGHT, OnUpdateCopyLinesFromRight)
        ON_COMMAND(ID_ADD_SYNCPOINT, OnAddSyncPoint)
        ON_COMMAND(ID_CLEAR_SYNCPOINTS, OnClearSyncPoints)
        ON_UPDATE_COMMAND_UI(ID_CLEAR_SYNCPOINTS, OnUpdateClearSyncPoints)
@@ -212,6 +221,7 @@ BEGIN_MESSAGE_MAP(CMergeEditView, CCrystalEditViewEx)
        ON_COMMAND(ID_FILE_OPEN_REGISTERED, OnOpenFile)
        ON_COMMAND(ID_FILE_OPEN_WITHEDITOR, OnOpenFileWithEditor)
        ON_COMMAND(ID_FILE_OPEN_WITH, OnOpenFileWith)
+       ON_COMMAND(ID_FILE_OPEN_PARENT_FOLDER, OnOpenParentFolder)
        ON_COMMAND(ID_SWAPPANES_SWAP12, OnViewSwapPanes12)
        ON_COMMAND(ID_SWAPPANES_SWAP23, OnViewSwapPanes23)
        ON_COMMAND(ID_SWAPPANES_SWAP13, OnViewSwapPanes13)
@@ -231,14 +241,6 @@ BEGIN_MESSAGE_MAP(CMergeEditView, CCrystalEditViewEx)
        ON_COMMAND(ID_VIEW_ZOOMNORMAL, OnViewZoomNormal)
        ON_COMMAND(ID_WINDOW_SPLIT, OnWindowSplit)
        ON_UPDATE_COMMAND_UI(ID_WINDOW_SPLIT, OnUpdateWindowSplit)
-       ON_COMMAND(ID_FIRSTFILE, OnFirstFile)
-       ON_UPDATE_COMMAND_UI(ID_FIRSTFILE, OnUpdateFirstFile)
-       ON_COMMAND(ID_PREVFILE, OnPrevFile)
-       ON_UPDATE_COMMAND_UI(ID_PREVFILE, OnUpdatePrevFile)
-       ON_COMMAND(ID_NEXTFILE, OnNextFile)
-       ON_UPDATE_COMMAND_UI(ID_NEXTFILE, OnUpdateNextFile)
-       ON_COMMAND(ID_LASTFILE, OnLastFile)
-       ON_UPDATE_COMMAND_UI(ID_LASTFILE, OnUpdateLastFile)
        ON_NOTIFY(NM_DBLCLK, AFX_IDW_STATUS_BAR, OnStatusBarDblClick)
        //}}AFX_MSG_MAP
 END_MESSAGE_MAP()
@@ -267,6 +269,15 @@ CCrystalTextBuffer *CMergeEditView::LocateTextBuffer()
        return GetDocument()->m_ptBuf[m_nThisPane].get();
 }
 
+void CMergeEditView::CopyProperties(CCrystalTextView* pSource)
+{
+       __super::CopyProperties(pSource);
+       auto pSourceEditView = dynamic_cast<decltype(this)>(pSource);
+       if (!pSourceEditView)
+               return;
+       m_bChangedSchemeManually = pSourceEditView->m_bChangedSchemeManually;
+}
+
 /**
  * @brief Update any resources necessary after a GUI language change
  */
@@ -299,15 +310,44 @@ CString CMergeEditView::GetLineText(int idx)
  */
 CString CMergeEditView::GetSelectedText()
 {
-       CPoint ptStart, ptEnd;
        CString strText;
-       GetSelection(ptStart, ptEnd);
+       auto [ptStart, ptEnd] = GetSelection();
        if (ptStart != ptEnd)
                GetTextWithoutEmptys(ptStart.y, ptStart.x, ptEnd.y, ptEnd.x, strText);
        return strText;
 }
 
 /**
+ * @brief Return number of selected characters
+ */
+std::pair<int, int> CMergeEditView::GetSelectedLineAndCharacterCount()
+{
+       auto [ptStart, ptEnd] = GetSelection();
+       int nCharsOrColumns =0;
+       int nSelectedLines = 0;
+       for (int nLine = ptStart.y; nLine <= ptEnd.y; ++nLine)
+       {
+               if ((GetLineFlags(nLine) & (LF_GHOST | LF_INVISIBLE)) == 0)
+               {
+                       int nLineLength = GetLineLength(nLine) + (m_pTextBuffer->GetLineEol(nLine)[0] ? 1 : 0);
+                       nCharsOrColumns += (nLine == ptEnd.y) ? ptEnd.x : nLineLength;
+                       if (nLine == ptStart.y)
+                               nCharsOrColumns -= ptStart.x;
+                       if (nLine < ptEnd.y || (ptStart != ptEnd && ptEnd.x > 0))
+                               ++nSelectedLines;
+               }
+       }
+       if (m_bRectangularSelection)
+       {
+               int nStartLeft, nStartRight, nEndLeft, nEndRight;
+               GetColumnSelection(ptStart.y, nStartLeft, nStartRight);
+               GetColumnSelection(ptEnd.y, nEndLeft, nEndRight);
+               nCharsOrColumns = (std::max)(nStartRight, nEndRight) - (std::min)(nStartLeft, nEndLeft);
+       }
+       return { nSelectedLines, nCharsOrColumns };
+}
+
+/**
  * @brief Get diffs inside selection.
  * @param [out] firstDiff First diff inside selection
  * @param [out] lastDiff Last diff inside selection
@@ -384,8 +424,7 @@ void CMergeEditView::GetFullySelectedDiffs(int & firstDiff, int & lastDiff, int
                return;
 
        int firstLine, lastLine;
-       CPoint ptStart, ptEnd;
-       GetSelection(ptStart, ptEnd);
+       auto [ptStart, ptEnd] = GetSelection();
        if (pptStart != nullptr)
                ptStart = *pptStart;
        if (pptEnd != nullptr)
@@ -496,13 +535,47 @@ void CMergeEditView::GetFullySelectedDiffs(int & firstDiff, int & lastDiff, int
        ASSERT(firstDiff != -1 ? firstWordDiff != -1 : true);
 }
 
+void CMergeEditView::GetSelectedDiffs(int & firstDiff, int & lastDiff)
+{
+       firstDiff = -1;
+       lastDiff = -1;
+
+       CMergeDoc *pd = GetDocument();
+       const int nDiffs = pd->m_diffList.GetSignificantDiffs();
+       if (nDiffs == 0)
+               return;
+
+       int firstLine, lastLine;
+       auto [ptStart, ptEnd] = GetSelection();
+       firstLine = ptStart.y;
+       lastLine = ptEnd.y;
+
+       firstDiff = pd->m_diffList.LineToDiff(firstLine);
+       if (firstDiff == -1)
+       {
+               firstDiff = pd->m_diffList.NextSignificantDiffFromLine(firstLine);
+               if (firstDiff == -1)
+                       return;
+       }
+       lastDiff = pd->m_diffList.LineToDiff(lastLine);
+       if (lastDiff == -1)
+               lastDiff = pd->m_diffList.PrevSignificantDiffFromLine(lastLine);
+       if (lastDiff < firstDiff)
+       {
+               firstDiff = -1;
+               return;
+       }
+
+       ASSERT(firstDiff == -1 ? (lastDiff  == -1) : true);
+       ASSERT(lastDiff  == -1 ? (firstDiff == -1) : true);
+}
+
 std::map<int, std::vector<int>> CMergeEditView::GetColumnSelectedWordDiffIndice()
 {
        CMergeDoc *pDoc = GetDocument();
        std::map<int, std::vector<int>> ret;
        std::map<int, std::vector<int> *> list;
-       CPoint ptStart, ptEnd;
-       GetSelection(ptStart, ptEnd);
+       auto [ptStart, ptEnd] = GetSelection();
        for (int nLine = ptStart.y; nLine <= ptEnd.y; ++nLine)
        {
                if (pDoc->m_diffList.LineToDiff(nLine) != -1)
@@ -661,9 +734,9 @@ std::vector<TEXTBLOCK> CMergeEditView::GetAdditionalTextBlocks (int nLineIndex)
        return blocks;
 }
 
-COLORREF CMergeEditView::GetColor(int nColorIndex)
+COLORREF CMergeEditView::GetColor(int nColorIndex) const
 {
-       switch (nColorIndex & ~COLORINDEX_APPLYFORCE)
+       switch (nColorIndex & ~COLORINDEX_MASK)
        {
        case COLORINDEX_HIGHLIGHTBKGND1:
                return m_cachedColors.clrSelWordDiff;
@@ -1096,8 +1169,7 @@ void CMergeEditView::OnUpdateCurdiff(CCmdUI* pCmdUI)
 void CMergeEditView::OnEditCopy()
 {
        CMergeDoc * pDoc = GetDocument();
-       CPoint ptSelStart, ptSelEnd;
-       GetSelection(ptSelStart, ptSelEnd);
+       auto [ptSelStart, ptSelEnd] = GetSelection();
 
        // Nothing selected
        if (ptSelStart == ptSelEnd)
@@ -1134,9 +1206,8 @@ void CMergeEditView::OnEditCut()
        if (!QueryEditable())
                return;
 
-       CPoint ptSelStart, ptSelEnd;
        CMergeDoc * pDoc = GetDocument();
-       GetSelection(ptSelStart, ptSelEnd);
+       auto [ptSelStart, ptSelEnd] = GetSelection();
 
        // Nothing selected
        if (ptSelStart == ptSelEnd)
@@ -1863,7 +1934,7 @@ void CMergeEditView::OnRButtonDown(UINT nFlags, CPoint point)
        DeselectDiffIfCursorNotInCurrentDiff();
 }
 
-void CMergeEditView::OnX2Y(int srcPane, int dstPane)
+void CMergeEditView::OnX2Y(int srcPane, int dstPane, bool selectedLineOnly)
 {
        // Check that right side is not readonly
        if (IsReadOnly(dstPane))
@@ -1883,29 +1954,41 @@ void CMergeEditView::OnX2Y(int srcPane, int dstPane)
                }
        }
 
-       CPoint ptStart, ptEnd;
-       GetSelection(ptStart, ptEnd);
+       auto [ptStart, ptEnd] = GetSelection();
        if (IsSelection() || pDoc->EqualCurrentWordDiff(srcPane, ptStart, ptEnd))
        {
                if (!m_bRectangularSelection)
                {
-                       int firstDiff, lastDiff, firstWordDiff, lastWordDiff;
-                       GetFullySelectedDiffs(firstDiff, lastDiff, firstWordDiff, lastWordDiff);
-                       if (firstDiff != -1 && lastDiff != -1)
+                       if (selectedLineOnly)
                        {
-                               CWaitCursor waitstatus;
-                               
-                               // Setting CopyFullLine (OPT_COPY_FULL_LINE)
-                               // restore old copy behaviour (always copy "full line" instead of "selected text only"), with a hidden option
-                               if (GetOptionsMgr()->GetBool(OPT_COPY_FULL_LINE))
+                               int firstDiff, lastDiff;
+                               GetSelectedDiffs(firstDiff, lastDiff);
+                               if (firstDiff != -1 && lastDiff != -1)
                                {
-                                       // old behaviour: copy full line
-                                       pDoc->CopyMultipleList(srcPane, dstPane, firstDiff, lastDiff);
+                                       CWaitCursor waitstatus;
+                                       pDoc->CopyMultiplePartialList(srcPane, dstPane, firstDiff, lastDiff, ptStart.y, ptEnd.y);
                                }
-                               else
+                       }
+                       else
+                       {
+                               int firstDiff, lastDiff, firstWordDiff, lastWordDiff;
+                               GetFullySelectedDiffs(firstDiff, lastDiff, firstWordDiff, lastWordDiff);
+                               if (firstDiff != -1 && lastDiff != -1)
                                {
-                                       // new behaviour: copy selected text only
-                                       pDoc->CopyMultipleList(srcPane, dstPane, firstDiff, lastDiff, firstWordDiff, lastWordDiff);
+                                       CWaitCursor waitstatus;
+                                       
+                                       // Setting CopyFullLine (OPT_COPY_FULL_LINE)
+                                       // restore old copy behaviour (always copy "full line" instead of "selected text only"), with a hidden option
+                                       if (GetOptionsMgr()->GetBool(OPT_COPY_FULL_LINE))
+                                       {
+                                               // old behaviour: copy full line
+                                               pDoc->CopyMultipleList(srcPane, dstPane, firstDiff, lastDiff);
+                                       }
+                                       else
+                                       {
+                                               // new behaviour: copy selected text only
+                                               pDoc->CopyMultipleList(srcPane, dstPane, firstDiff, lastDiff, firstWordDiff, lastWordDiff);
+                                       }
                                }
                        }
                }
@@ -1922,8 +2005,16 @@ void CMergeEditView::OnX2Y(int srcPane, int dstPane)
        }
        else if (currentDiff != -1 && pDoc->m_diffList.IsDiffSignificant(currentDiff))
        {
-               CWaitCursor waitstatus;
-               pDoc->ListCopy(srcPane, dstPane, currentDiff);
+               if (selectedLineOnly)
+               {
+                       CWaitCursor waitstatus;
+                       pDoc->PartialListCopy(srcPane, dstPane, currentDiff, ptStart.y, ptEnd.y);
+               }
+               else
+               {
+                       CWaitCursor waitstatus;
+                       pDoc->ListCopy(srcPane, dstPane, currentDiff);
+               }
        }
 }
 
@@ -1935,8 +2026,7 @@ void CMergeEditView::OnUpdateX2Y(int dstPane, CCmdUI* pCmdUI)
                // If one or more diffs inside selection OR
                // there is an active diff OR
                // cursor is inside diff
-               CPoint ptStart, ptEnd;
-               GetSelection(ptStart, ptEnd);
+               auto [ptStart, ptEnd] = GetSelection();
                if (IsSelection() || GetDocument()->EqualCurrentWordDiff(m_nThisPane, ptStart, ptEnd))
                {
                        if (m_bCurrentLineIsDiff || (m_pTextBuffer->GetLineFlags(m_ptSelStart.y) & LF_NONTRIVIAL_DIFF) != 0)
@@ -1987,6 +2077,18 @@ void CMergeEditView::OnUpdateL2r(CCmdUI* pCmdUI)
        OnUpdateX2Y(m_nThisPane < GetDocument()->m_nBuffers - 1 ? m_nThisPane + 1 : GetDocument()->m_nBuffers - 1, pCmdUI);
 }
 
+void CMergeEditView::OnLinesL2r()
+{
+       int dstPane = (m_nThisPane < GetDocument()->m_nBuffers - 1) ? m_nThisPane + 1 : GetDocument()->m_nBuffers - 1;
+       int srcPane = dstPane - 1;
+       OnX2Y(srcPane, dstPane, true);
+}
+
+void CMergeEditView::OnUpdateLinesL2r(CCmdUI* pCmdUI)
+{
+       OnUpdateX2Y(m_nThisPane < GetDocument()->m_nBuffers - 1 ? m_nThisPane + 1 : GetDocument()->m_nBuffers - 1, pCmdUI);
+}
+
 /**
  * @brief Copy diff from right pane to left pane
  *
@@ -2013,6 +2115,18 @@ void CMergeEditView::OnUpdateR2l(CCmdUI* pCmdUI)
        OnUpdateX2Y(m_nThisPane > 0 ? m_nThisPane - 1 : 0, pCmdUI);
 }
 
+void CMergeEditView::OnLinesR2l()
+{
+       int dstPane = (m_nThisPane > 0) ? m_nThisPane - 1 : 0;
+       int srcPane = dstPane + 1;
+       OnX2Y(srcPane, dstPane, true);
+}
+
+void CMergeEditView::OnUpdateLinesR2l(CCmdUI* pCmdUI)
+{
+       OnUpdateX2Y(m_nThisPane > 0 ? m_nThisPane - 1 : 0, pCmdUI);
+}
+
 void CMergeEditView::OnCopyFromLeft()
 {
        int dstPane = m_nThisPane;
@@ -2032,6 +2146,25 @@ void CMergeEditView::OnUpdateCopyFromLeft(CCmdUI* pCmdUI)
                OnUpdateX2Y(dstPane, pCmdUI);
 }
 
+void CMergeEditView::OnCopyLinesFromLeft()
+{
+       int dstPane = m_nThisPane;
+       int srcPane = dstPane - 1;
+       if (srcPane < 0)
+               return;
+       OnX2Y(srcPane, dstPane, true);
+}
+
+void CMergeEditView::OnUpdateCopyLinesFromLeft(CCmdUI* pCmdUI)
+{
+       int dstPane = m_nThisPane;
+       int srcPane = dstPane - 1;
+       if (srcPane < 0)
+               pCmdUI->Enable(false);
+       else
+               OnUpdateX2Y(dstPane, pCmdUI);
+}
+
 void CMergeEditView::OnCopyFromRight()
 {
        int dstPane = m_nThisPane;
@@ -2051,6 +2184,25 @@ void CMergeEditView::OnUpdateCopyFromRight(CCmdUI* pCmdUI)
                OnUpdateX2Y(dstPane, pCmdUI);
 }
 
+void CMergeEditView::OnCopyLinesFromRight()
+{
+       int dstPane = m_nThisPane;
+       int srcPane = dstPane + 1;
+       if (srcPane >= GetDocument()->m_nBuffers)
+               return;
+       OnX2Y(srcPane, dstPane, true);
+}
+
+void CMergeEditView::OnUpdateCopyLinesFromRight(CCmdUI* pCmdUI)
+{
+       int dstPane = m_nThisPane;
+       int srcPane = dstPane + 1;
+       if (srcPane >= GetDocument()->m_nBuffers)
+               pCmdUI->Enable(false);
+       else
+               OnUpdateX2Y(dstPane, pCmdUI);
+}
+
 /**
  * @brief Copy all diffs from right pane to left pane
  */
@@ -2109,98 +2261,6 @@ void CMergeEditView::OnUpdateAllRight(CCmdUI* pCmdUI)
 }
 
 /**
- * @brief Move to next file
- */
-void CMergeEditView::OnNextFile()
-{
-       CMergeDoc* pd = GetDocument();
-       CDirDoc* pDirDoc = pd->GetDirDoc();
-       if (pDirDoc)
-       {
-               pDirDoc->MoveToNextFile(pd);
-       }
-}
-
-/**
- * @brief Called when Move to next file is updated
- */
-void CMergeEditView::OnUpdateNextFile(CCmdUI* pCmdUI)
-{
-       CMergeDoc* pd = GetDocument();
-       bool enabled = !pd->GetDirDoc()->IsLastFile();
-       pCmdUI->Enable(enabled);
-}
-
-/**
- * @brief Move to previous file
- */
-void CMergeEditView::OnPrevFile()
-{
-       CMergeDoc* pd = GetDocument();
-       CDirDoc* pDirDoc = pd->GetDirDoc();
-       if (pDirDoc)
-       {
-               pDirDoc->MoveToPrevFile(pd);
-       }
-}
-
-/**
- * @brief Called when Move to previous file is updated
- */
-void CMergeEditView::OnUpdatePrevFile(CCmdUI* pCmdUI)
-{
-       CMergeDoc* pd = GetDocument();  
-       bool enabled = !pd->GetDirDoc()->IsFirstFile();
-       pCmdUI->Enable(enabled);
-}
-
-/**
- * @brief Move to first file
- */
-void CMergeEditView::OnFirstFile()
-{
-       CMergeDoc* pd = GetDocument();
-       CDirDoc* pDirDoc = pd->GetDirDoc();
-       if (pDirDoc)
-       {
-               pDirDoc->MoveToFirstFile(pd);
-       }
-}
-
-/**
- * @brief Called when Move to first file is updated
- */
-void CMergeEditView::OnUpdateFirstFile(CCmdUI* pCmdUI)
-{
-       CMergeDoc* pd = GetDocument();  
-       bool enabled = !pd->GetDirDoc()->IsFirstFile();
-       pCmdUI->Enable(enabled);
-}
-
-/**
- * @brief Move to last file
- */
-void CMergeEditView::OnLastFile()
-{
-       CMergeDoc* pd = GetDocument();
-       CDirDoc* pDirDoc = pd->GetDirDoc();
-       if (pDirDoc)
-       {
-               pDirDoc->MoveToLastFile(pd);
-       }
-}
-
-/**
- * @brief Called when Move to last file item is updated
- */
-void CMergeEditView::OnUpdateLastFile(CCmdUI* pCmdUI)
-{
-       CMergeDoc* pd = GetDocument();
-       bool enabled = !pd->GetDirDoc()->IsLastFile();
-       pCmdUI->Enable(enabled);
-}
-
-/**
  * @brief Do Auto merge
  */
 void CMergeEditView::OnAutoMerge()
@@ -2287,7 +2347,7 @@ void CMergeEditView::OnEditOperation(int nAction, LPCTSTR pszText, size_t cchTex
        pDoc->UpdateHeaderPath(m_nThisPane);
 
        // If automatic rescan enabled, rescan after edit events
-       if (m_bAutomaticRescan)
+       if (pDoc->GetAutomaticRescan())
        {
                // keep document up to date     
                // (Re)start timer to rescan only when user edits text
@@ -2741,6 +2801,7 @@ void CMergeEditView::OnUpdateCaret()
        int column = -1;
        int columns = -1;
        int curChar = -1;
+       auto [selectedLines, selectedChars] = GetSelectedLineAndCharacterCount();
        DWORD dwLineFlags = 0;
 
        dwLineFlags = m_pTextBuffer->GetLineFlags(nScreenLine);
@@ -2769,7 +2830,8 @@ void CMergeEditView::OnUpdateCaret()
                        sEol = _T("hidden");
        }
        m_piMergeEditStatus->SetLineInfo(sLine, column, columns,
-               curChar, chars, sEol, GetDocument()->m_ptBuf[m_nThisPane]->getCodepage(), GetDocument()->m_ptBuf[m_nThisPane]->getHasBom());
+               curChar, chars, selectedLines, selectedChars,
+               sEol, GetDocument()->m_ptBuf[m_nThisPane]->getCodepage(), GetDocument()->m_ptBuf[m_nThisPane]->getHasBom());
 
        // Is cursor inside difference?
        if (dwLineFlags & LF_NONTRIVIAL_DIFF)
@@ -2987,11 +3049,15 @@ void CMergeEditView::OnContextMenu(CWnd* pWnd, CPoint point)
        {
                menu.RemoveMenu(ID_COPY_FROM_RIGHT, MF_BYCOMMAND);
                menu.RemoveMenu(ID_COPY_FROM_LEFT, MF_BYCOMMAND);
+               menu.RemoveMenu(ID_COPY_LINES_FROM_RIGHT, MF_BYCOMMAND);
+               menu.RemoveMenu(ID_COPY_LINES_FROM_LEFT, MF_BYCOMMAND);
        }
        if (m_nThisPane == GetDocument()->m_nBuffers - 1)
        {
                menu.RemoveMenu(ID_COPY_FROM_LEFT, MF_BYCOMMAND);
                menu.RemoveMenu(ID_COPY_FROM_RIGHT, MF_BYCOMMAND);
+               menu.RemoveMenu(ID_COPY_LINES_FROM_RIGHT, MF_BYCOMMAND);
+               menu.RemoveMenu(ID_COPY_LINES_FROM_LEFT, MF_BYCOMMAND);
        }
 
        // Remove "Go to Moved Line Between Middle and Right" if in 2-way file comparison.
@@ -3406,8 +3472,6 @@ void CMergeEditView::RefreshOptions()
        RENDERING_MODE nRenderingMode = static_cast<RENDERING_MODE>(GetOptionsMgr()->GetInt(OPT_RENDERING_MODE));
        SetRenderingMode(nRenderingMode);
 
-       m_bAutomaticRescan = GetOptionsMgr()->GetBool(OPT_AUTOMATIC_RESCAN);
-
        if (GetOptionsMgr()->GetInt(OPT_TAB_TYPE) == 0)
                SetInsertTabs(true);
        else
@@ -3417,6 +3481,19 @@ void CMergeEditView::RefreshOptions()
 
        if (!GetOptionsMgr()->GetBool(OPT_SYNTAX_HIGHLIGHT))
                SetTextType(CrystalLineParser::SRC_PLAIN);
+       else if (!m_bChangedSchemeManually)
+       {
+               // The syntax highlighting scheme should only be applied if it has not been manually changed.
+               String fileName = GetDocument()->m_filePaths[m_nThisPane];
+               String sExt;
+               paths::SplitFilename(fileName, nullptr, nullptr, &sExt);
+               CrystalLineParser::TextDefinition* def = CrystalLineParser::GetTextType(sExt.c_str());
+               if (def != nullptr)
+                       SetTextType(def->type);
+               else
+                       SetTextType(CrystalLineParser::SRC_PLAIN);
+               SetDisableBSAtSOL(false);
+       }
 
        SetWordWrapping(GetOptionsMgr()->GetBool(OPT_WORDWRAP));
        SetViewLineNumbers(GetOptionsMgr()->GetBool(OPT_VIEW_LINENUMBERS));
@@ -3732,14 +3809,12 @@ void CMergeEditView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
  */
 void CMergeEditView::OnEditCopyLineNumbers()
 {
-       CPoint ptStart;
-       CPoint ptEnd;
        CString strText;
        CString strLine;
        CString strNumLine;
 
        CMergeDoc *pDoc = GetDocument();
-       GetSelection(ptStart, ptEnd);
+       auto [ptStart, ptEnd] = GetSelection();
 
        // Get last selected line (having widest linenumber)
        int line = pDoc->m_ptBuf[m_nThisPane]->ComputeRealLine(ptEnd.y);
@@ -3784,13 +3859,7 @@ void CMergeEditView::OnOpenFile()
        String sFileName = pDoc->m_filePaths[m_nThisPane];
        if (sFileName.empty())
                return;
-       HINSTANCE rtn = ShellExecute(::GetDesktopWindow(), _T("edit"), sFileName.c_str(),
-                       0, 0, SW_SHOWNORMAL);
-       if (reinterpret_cast<uintptr_t>(rtn) == SE_ERR_NOASSOC)
-               rtn = ShellExecute(::GetDesktopWindow(), _T("open"), sFileName.c_str(),
-                        0, 0, SW_SHOWNORMAL);
-       if (reinterpret_cast<uintptr_t>(rtn) == SE_ERR_NOASSOC)
-               OnOpenFileWith();
+       shell::Edit(sFileName.c_str());
 }
 
 /**
@@ -3804,14 +3873,7 @@ void CMergeEditView::OnOpenFileWith()
        String sFileName = pDoc->m_filePaths[m_nThisPane];
        if (sFileName.empty())
                return;
-
-       CString sysdir;
-       if (!GetSystemDirectory(sysdir.GetBuffer(MAX_PATH), MAX_PATH))
-               return;
-       sysdir.ReleaseBuffer();
-       CString arg = (CString)_T("shell32.dll,OpenAs_RunDLL ") + sFileName.c_str();
-       ShellExecute(::GetDesktopWindow(), 0, _T("RUNDLL32.EXE"), arg,
-                       sysdir, SW_SHOWNORMAL);
+       shell::OpenWith(sFileName.c_str());
 }
 
 /**
@@ -3831,6 +3893,21 @@ void CMergeEditView::OnOpenFileWithEditor()
 }
 
 /**
+ * @brief Open parent folder of active file
+ */
+void CMergeEditView::OnOpenParentFolder()
+{
+       CMergeDoc * pDoc = GetDocument();
+       ASSERT(pDoc != nullptr);
+
+       String sFileName = pDoc->m_filePaths[m_nThisPane];
+       if (sFileName.empty())
+               return;
+
+       shell::OpenParentFolder(sFileName.c_str());
+}
+
+/**
  * @brief Force repaint of the location pane.
  */
 void CMergeEditView::RepaintLocationPane()
@@ -4212,9 +4289,6 @@ void CMergeEditView::DocumentsLoaded()
                SetTopMargin(false);
        }
 
-       // Enable/disable automatic rescan (rescanning after edit)
-       EnableRescan(GetOptionsMgr()->GetBool(OPT_AUTOMATIC_RESCAN));
-
        // SetTextType will revert to language dependent defaults for tab
        SetTabSize(GetOptionsMgr()->GetInt(OPT_TAB_SIZE));
        SetViewTabs(GetOptionsMgr()->GetBool(OPT_VIEW_WHITESPACE));
@@ -4333,6 +4407,7 @@ void CMergeEditView::OnChangeScheme(UINT nID)
                        {
                                pView->SetTextType(CrystalLineParser::TextType(nID - ID_COLORSCHEME_FIRST));
                                pView->SetDisableBSAtSOL(false);
+                               pView->m_bChangedSchemeManually = true;
                        }
                }
 
@@ -4427,7 +4502,9 @@ void CMergeEditView::ZoomText(short amount)
 
        if ( amount == 0)
        {
-               nPointSize = -MulDiv(GetOptionsMgr()->GetInt(OPT_FONT_FILECMP + OPT_FONT_HEIGHT), 72, nLogPixelsY);
+               nPointSize = GetOptionsMgr()->GetInt(OPT_FONT_FILECMP + OPT_FONT_POINTSIZE);
+               if (nPointSize ==  0)
+                       nPointSize = -MulDiv(GetOptionsMgr()->GetInt(OPT_FONT_FILECMP + OPT_FONT_HEIGHT), 72, nLogPixelsY);
        }
 
        nPointSize += amount;
@@ -4560,8 +4637,7 @@ void CMergeEditView::ScrollToSubLine(int nNewTopLine, bool bNoSmoothScroll /*= F
                if (EnsureInDiff(pt))
                        SetCursorPos(pt);
 
-               CPoint ptSelStart, ptSelEnd;
-               GetSelection(ptSelStart, ptSelEnd);
+               auto [ptSelStart, ptSelEnd] = GetSelection();
                if (EnsureInDiff(ptSelStart) || EnsureInDiff(ptSelEnd))
                        SetSelection(ptSelStart, ptSelEnd);
        }