Bug 82662 - [PATCH] new feature: (global) cursor position history
Summary: [PATCH] new feature: (global) cursor position history
Status: RESOLVED INTENTIONAL
Alias: None
Product: kdevelop
Classification: Applications
Component: bookmarks part (show other bugs)
Version: unspecified
Platform: openSUSE Linux
: NOR wishlist
Target Milestone: ---
Assignee: kdevelop-bugs-null
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-06-01 22:19 UTC by andreas braendle
Modified: 2006-12-18 19:00 UTC (History)
0 users

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description andreas braendle 2004-06-01 22:19:21 UTC
Version:            (using KDE KDE 3.2.1)
Installed from:    SuSE RPMs
OS:                Linux

i've written a class (some months ago)
someone must intergrate it into kdevelop

it's a pretty sophisticated feature already.

description&howto is included

-----------------
[...]

// Documentation:

// PURPOSE:
// implements a global CursorPositionHistory for qeditor (?) etc.
// usful when working with large projects/files, and having to do changes in
several files
// makes finding interesting positions again a lot easier (for example while
browsing the code);
// also useful during finding out how the code of a certain program is
working
// also useful when working only with a large single file, as i found out :)
// can be more practical than & is not intended as a substitute for bookmarks

Special features:
- if navigating within a "block" of +/- 7 lines no additional history entry
is inserted
- if navigating back and then changing the cursor position, the "future"
isn't
deleted
- NavigateLeave deletes the current entry out of the history list (=leave
this position),
(it also pushes it onto a small stack -> NavigatePop to get it back)


**************************
I would have proposed to use the 4 keys Ctrl-Alt-Left/Right/Up/Down, but they seem to be already
used for other purposes.

...Ctrl-Alt-Shift-Left/Right are also already used

other proposals:

Ctrl-Alt-Shift-j/k/l/i
Ctrl-Alt-4/5/6/8 (Numpad)
etc.

**************************
("light" version with 2 or 3 keys possible)

QEditorWidget* NavigateBack(int &line, int &column);     // Ctrl-Alt-Left
for example
 QEditorWidget* NavigateLeave(int &line, int &column);    // Ctrl-Alt-Up
for example
 QEditorWidget* NavigateForward(int &line, int &column);  // Ctrl-Alt-Right
for example
QEditorWidget* NavigatePop(int &line, int &column);      // Ctrl-Alt-Down
for example (3key-version: optional)



stack:   i
Pos2     |
Pos1     v
  |
  *---------------------*  UP
                        |  DOWN
                        |
                        |
history <<<<<-------- current ------------>>>> future

 LEFT                                     RIGHT



KEYPRESSED-EVENT: (PSEUDOCODE)
int l,c;
QEditorWidget* p;

if (p=NavigateBack(l,c)) {setviewactive?(p); setcursor(p,l,c); }



**************************


// INTEGRATION: [see source files]
....
// perhaps the Application/mainwindow should catch these events and then
change to the correct
// editor-window+line+column

// SideEffects/NECESSARY CHANGES to rest of the Editor-code:
// uses QEditorWiget* pointers to identify which of the currently open files
is meant
// Editor Codes has to inform this Class and use it, and also inform it when
a file is closed
// Application has to create one object of this class
Comment 1 andreas braendle 2004-06-01 22:20:49 UTC
// CURSHIST.CPP

#include "curshist.h"
#include <string.h>


CGlobalCursorPosHistory::CGlobalCursorPosHistory()
{
   m_hist = new CursHistEntry[GCPH_HISTSZ+2];  // +2 savety (+1 needed)
   num=0; curr=0;
   
   m_stack = new CursHistEntry[GCPH_HSTACK];
   num_s=0;               
}


CGlobalCursorPosHistory::~CGlobalCursorPosHistory()
{
   delete[] m_hist;
}

void CGlobalCursorPosHistory::CursorChanged(QEditorWidget* FileId, int line, int column)
{
 int newidx;
 int currline=m_hist[curr].LineCol/256;
 if (line>currline-GCPH_BLOCK && line<currline+GCPH_BLOCK)  // replace Entry -- if we are withing same BLOCK
    newidx = curr;
 else {
   // make room for new entry
   newidx=curr+1;
   memcpy((void*)&m_hist[newidx+1],(void*)&m_hist[newidx], (num-newidx-1)* sizeof(CursHistEntry));
   // remark: might lead to GCPH_HISTSZ+1 entries, but this is ok!
   num++;

   // if too much entries, delete either the first or the last
   if (GCPH_HISTSZ>num) {

     if (newidx>(3*GCPH_HISTSZ)/5)  // 60 % for history, 40 % for future
     {
       memcpy((void*)&m_hist[0],(void*)&m_hist[1], GCPH_HISTSZ*sizeof(CursHistEntry)); // delete first entry
       newidx--;
     } //else: do nothing           // = delete last entry

     num=GCPH_HISTSZ;
   }
 }

 if (line>0xFFFFFF) line=0xFFFFFF;
 if (line<0) line=0;
 if (column>0xFF) column=0xFF;
 if (column<0) column=0;

 m_hist[newidx].FileId=FileId;
 m_hist[newidx].LineCol=256*line+column; 
}

void CGlobalCursorPosHistory::FileClosed(QEditorWidget* FileId)
{
 for (int i=0; i<num; i++)
 {
   if (m_hist[i].FileId==FileId) {
     memcpy((void*)&m_hist[i],(void*)&m_hist[i+1], (num-i-1)*sizeof(CursHistEntry));
     num--;
     if (curr>i) curr--;
     if (curr>num-1) curr--;
   }
 }
}


/* 
The following functions return:
 the editor view to go to
 line+column (returned by reference)

editor view=NULL always means don't change cursor position!
*/
QEditorWidget* CGlobalCursorPosHistory::NavigateBack(int &line, int &column)
{
if (num<=0) return NULL;  // NULL: No History Entries exist yet, Navigation not possible

if (curr>=1) curr--;

line  =m_hist[curr].LineCol / 256;
column=m_hist[curr].LineCol % 256;
return m_hist[curr].FileId;
}


QEditorWidget* CGlobalCursorPosHistory::NavigateForward(int &line, int &column)
{
if (num<=0) return NULL;  // NULL: No History Entries exist yet

if (curr<num-1) curr++;

line  =m_hist[curr].LineCol / 256;
column=m_hist[curr].LineCol % 256;
return m_hist[curr].FileId;
}


QEditorWidget* CGlobalCursorPosHistory::NavigateLeave(int &line, int &column) //PUSH
{
if (num<=0) return NULL;  // NULL: No History Entries exist yet, Navigation not possible

// PUSH curr ON stack
// make space for one entry at 0
memcpy((void*)&m_stack[1],(void*)&m_stack[0], (GCPH_HSTACK-1)*sizeof(CursHistEntry)); 

m_stack[0].LineCol=m_hist[curr].LineCol;
m_stack[0].FileId =m_hist[curr].FileId;
num_s++; if (num_s>GCPH_HSTACK) num_s=GCPH_HSTACK;
num--;

return NavigateBack(line,column); // new position is curr-1
}


QEditorWidget* CGlobalCursorPosHistory::NavigatePop(int &line, int &column) //POP
{
if (num_s<=0) return NULL;  // NULL: stack empty, Navigation not possible

// get topmost stack entry (=m_stack[0])
line            =m_stack[0].LineCol / 256;
column          =m_stack[0].LineCol % 256;
QEditorWidget* p=m_stack[0].FileId;

// insert the entry in history list
CursorChanged(p,line,column); 

// delete topmost stack entry (=m_stack[0])
memcpy((void*)&m_stack[0],(void*)&m_stack[1], (GCPH_HSTACK-1)*sizeof(CursHistEntry)); 
num_s--;

return p;
}
Comment 2 andreas braendle 2004-06-01 22:21:46 UTC
// CURSHIST.H

#ifndef CURSHIST_H
#define CURSHIST_H


// written by (C) Andreas Brändle <abraendle@gmx.de>  10.01.04
// published under GPL

// TODO: Implement this useful feature also into other IDEs/editors!!

/*

You need:

* 4 application-global keys: Left, Right, Up, Down
(Light-version 2 keys: Right, Left  -also possible)

* one application-global object of this class

* the editor-views must know about this object and inform it when the cursor position has
  changed, because - a character was entered
                   - cursor keys pressed
  especially NOT when - Page/UpDown pressed
                      - Mouse clicked

  also when a file/view is closed

* catch the events for the 4 keys globally and change to the appropriate view+cursorposition

thats all...

*/

// TODO: IMPORTANT! change the "QEditorWiget*"-pointers to what is needed to identify the view!
class QEditorWidget; //DEL THIS LINE!!

/**INTERNAL**/

struct CursHistEntry {
  QEditorWidget* FileId;
  int LineCol;  // (Line 0..2^24-1) *256 + Column 0..255 to save memory
};

const int GCPH_BLOCK=7;    // num of lines within which a cursor movement is not to be stored twice
const int GCPH_HISTSZ=260; // size of history list
const int GCPH_HSTACK=16;  // size of history stack

/***BEGIN****/

/* Purpose: 
     Implements a global cursor position history 
*/
class CGlobalCursorPosHistory {
public:
    CGlobalCursorPosHistory();
    ~CGlobalCursorPosHistory();

	// store/update positions
    void CursorChanged(QEditorWidget* FileId, int line, int column);   // inform this class!
    void FileClosed(QEditorWidget* FileId);                            // clean up history list
	// get new position
	QEditorWidget* NavigateBack(int &line, int &column);     // Ctrl-Alt-Left  for example
	QEditorWidget* NavigateLeave(int &line, int &column);    // Ctrl-Alt-Up    for example
    QEditorWidget* NavigateForward(int &line, int &column);  // Ctrl-Alt-Right for example
	QEditorWidget* NavigatePop(int &line, int &column);      // Ctrl-Alt-Down  for example 


private:
    CursHistEntry* m_hist;
	CursHistEntry* m_stack;
    int num;                  // number of valid entries
	int curr;                 // entry with last known cursor position (current)
	int num_s;                // number of valid entries in stack
};


/****END*****/


#endif CURSHIST_H
Comment 3 andreas braendle 2004-06-01 22:23:56 UTC
the class itself is rather simple
not much is needed apart from 4 keys & the ability to set a specific view+line+column
Comment 4 andreas braendle 2004-06-01 22:31:06 UTC
"Also, History Back/Forward buttons will helps along with this "hypercode" walking." in Bug 62711
Comment 5 andreas braendle 2004-07-05 18:43:03 UTC
you don't understand this feature... or why is nobody interested???

it's such a nice feature for an editor, IMHO...
Comment 6 Jens Dagerbo 2006-12-18 19:00:05 UTC
No idea why this was put to the bookmarks plugin. Also, the patch seems to reference the QEditor, which has been removed. Closing.