SF.net SVN: geany-plugins:[2032] trunk/geany-plugins/geanynumberedbookmarks
wfraser at users.sourceforge.net
wfraser at xxxxx
Sun Apr 17 12:55:34 UTC 2011
Revision: 2032
http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=2032&view=rev
Author: wfraser
Date: 2011-04-17 12:55:33 +0000 (Sun, 17 Apr 2011)
Log Message:
-----------
Added geanymacro and geanynumberedbookmarks as splitting geanycfp
Added Paths:
-----------
trunk/geany-plugins/geanynumberedbookmarks/src/
trunk/geany-plugins/geanynumberedbookmarks/src/Makefile.am
trunk/geany-plugins/geanynumberedbookmarks/src/geanynumberedbookmarks.c
Added: trunk/geany-plugins/geanynumberedbookmarks/src/Makefile.am
===================================================================
--- trunk/geany-plugins/geanynumberedbookmarks/src/Makefile.am (rev 0)
+++ trunk/geany-plugins/geanynumberedbookmarks/src/Makefile.am 2011-04-17 12:55:33 UTC (rev 2032)
@@ -0,0 +1,10 @@
+include $(top_srcdir)/build/vars.build.mk
+
+if ENABLE_GEANYNUMBEREDBOOKMARKS
+geanyplugins_LTLIBRARIES = geanynumberedbookmarks.la
+else
+EXTRA_LTLIBRARIES = geanynumberedbookmarks.la
+endif
+
+geanynumberedbookmarks_la_SOURCES = geanynumberedbookmarks.c
+geanynumberedbookmarks_la_LIBADD = $(COMMONLIBS)
Property changes on: trunk/geany-plugins/geanynumberedbookmarks/src/Makefile.am
___________________________________________________________________
Added: svn:executable
+ *
Added: trunk/geany-plugins/geanynumberedbookmarks/src/geanynumberedbookmarks.c
===================================================================
--- trunk/geany-plugins/geanynumberedbookmarks/src/geanynumberedbookmarks.c (rev 0)
+++ trunk/geany-plugins/geanynumberedbookmarks/src/geanynumberedbookmarks.c 2011-04-17 12:55:33 UTC (rev 2032)
@@ -0,0 +1,1072 @@
+/*
+ * This code is supplied as is, and is used at your own risk.
+ * The GNU GPL version 2 rules apply to this code (see http://fsf.org/>
+ * You can alter it, and pass it on as you want.
+ * If you alter it, or pass it on, the only restriction is that this disclamour and licence be
+ * left intact
+ *
+ * william.fraser at virgin.net
+ * 2010-11-01
+*/
+
+
+#include "geanyplugin.h"
+#include "utils.h"
+#include "Scintilla.h"
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+static const gint base64_char_to_int[]=
+{
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
+ 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
+ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255
+};
+
+static const gchar base64_int_to_char[]=
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* offset for marker numbers used - to bypass markers used by normal bookmarksetc */
+#define BOOKMARK_BASE 10
+
+/* define structures used in this plugin */
+typedef struct FileData
+{
+ gchar *pcFileName; /* holds filename */
+ gint iBookmark[10]; /* holds bookmark lines or -1 for not set */
+ gchar *pcFolding; /* holds which folds are open and which not */
+ gint LastChangedTime; /* time file was last changed by this editor */
+ struct FileData * NextNode;
+} FileData;
+
+/* structure to hold list of Scintilla objects that have had icons set for bookmarks */
+typedef struct SCIPOINTERHOLDER
+{
+ ScintillaObject* sci;
+ struct SCIPOINTERHOLDER * NextNode;
+} SCIPOINTERHOLDER;
+
+GeanyPlugin *geany_plugin;
+GeanyData *geany_data;
+GeanyFunctions *geany_functions;
+
+PLUGIN_VERSION_CHECK(147)
+
+PLUGIN_SET_INFO("Numbered Bookmarks",_("Numbered Bookmarks for Geany"),
+ "0.1","William Fraser <william.fraser at virgin.net>");
+
+/* Plugin user alterable settings */
+static gboolean bCenterWhenGotoBookmark=TRUE;
+static gboolean bRememberFolds=TRUE;
+
+/* internal variables */
+static gint iShiftNumbers[]={41,33,34,163,36,37,94,38,42,40};
+static SCIPOINTERHOLDER *sciList=NULL;
+static FileData *fdKnownFilesSettings=NULL;
+static gulong key_release_signal_id;
+
+/* default config file */
+const gchar default_config[] =
+ "[Settings]\n"
+ "Center_When_Goto_Bookmark = true\n"
+ "Remember_Folds = true\n"
+ "[FileData]";
+
+/* Definitions for bookmark images */
+static gchar * aszMarkerImage0[] =
+{
+ "17 14 3 1", /* width height colours characters-per-pixel */
+ ". c None",
+ "B c #000000",
+ "* c #FFFF00",
+ "...BBBBBBBBBB....",
+ "..B**********B...",
+ ".B****BBBB****B..",
+ "B****BB**BB****B.",
+ "B****B****B****B.",
+ "B****B****B****B.",
+ "B****B*BB*B****B.",
+ "B****B****B****B.",
+ "B****B****B****B.",
+ "B****B****B****B.",
+ "B****BB**BB****B.",
+ ".B****BBBB****B..",
+ "..B**********B...",
+ "...BBBBBBBBBB...."
+};
+static gchar * aszMarkerImage1[] =
+{
+ "17 14 3 1", /* width height colours characters-per-pixel */
+ ". c None",
+ "B c #000000",
+ "* c #FFFF00",
+ "...BBBBBBBBBB....",
+ "..B**********B...",
+ ".B*****BB*****B..",
+ "B*****BBB******B.",
+ "B*******B******B.",
+ "B*******B******B.",
+ "B*******B******B.",
+ "B*******B******B.",
+ "B*******B******B.",
+ "B*******B******B.",
+ "B*******B******B.",
+ ".B****BBBBB***B..",
+ "..B**********B...",
+ "...BBBBBBBBBB...."
+};
+static gchar * aszMarkerImage2[] =
+{
+ "17 14 3 1", /* width height colours characters-per-pixel */
+ ". c None",
+ "B c #000000",
+ "* c #FFFF00",
+ "...BBBBBBBBBB....",
+ "..B**********B...",
+ ".B****BBBB****B..",
+ "B****BB**BB****B.",
+ "B*********B****B.",
+ "B*********B****B.",
+ "B********BB****B.",
+ "B*******BB*****B.",
+ "B******BB******B.",
+ "B*****BB*******B.",
+ "B****BB********B.",
+ ".B***BBBBBB***B..",
+ "..B**********B...",
+ "...BBBBBBBBBB...."
+};
+static gchar * aszMarkerImage3[] =
+{
+ "17 14 3 1", /* width height colours characters-per-pixel */
+ ". c None",
+ "B c #000000",
+ "* c #FFFF00",
+ "...BBBBBBBBBB....",
+ "..B**********B...",
+ ".B****BBBB****B..",
+ "B****BB**BB****B.",
+ "B*********B****B.",
+ "B********BB****B.",
+ "B*****BBBB*****B.",
+ "B********BB****B.",
+ "B*********B****B.",
+ "B*********B****B.",
+ "B****BB**BB****B.",
+ ".B****BBBB****B..",
+ "..B**********B...",
+ "...BBBBBBBBBB...."
+};
+static gchar * aszMarkerImage4[] =
+{
+ "17 14 3 1", /* width height colours characters-per-pixel */
+ ". c None",
+ "B c #000000",
+ "* c #FFFF00",
+ "...BBBBBBBBBB....",
+ "..B**********B...",
+ ".B******BB****B..",
+ "B*******BB*****B.",
+ "B******B*B*****B.",
+ "B******B*B*****B.",
+ "B*****B**B*****B.",
+ "B*****B**B*****B.",
+ "B****BBBBBB****B.",
+ "B********B*****B.",
+ "B********B*****B.",
+ ".B*******B****B..",
+ "..B**********B...",
+ "...BBBBBBBBBB...."
+};
+static gchar * aszMarkerImage5[] =
+{
+ "17 14 3 1", /* width height colours characters-per-pixel */
+ ". c None",
+ "B c #000000",
+ "* c #FFFF00",
+ "...BBBBBBBBBB....",
+ "..B**********B...",
+ ".B***BBBBBB***B..",
+ "B****B*********B.",
+ "B****B*********B.",
+ "B****B*********B.",
+ "B****BBBBB*****B.",
+ "B********BB****B.",
+ "B*********B****B.",
+ "B*********B****B.",
+ "B****BB**BB****B.",
+ ".B****BBBB****B..",
+ "..B**********B...",
+ "...BBBBBBBBBB...."
+};
+static gchar * aszMarkerImage6[] =
+{
+ "17 14 3 1", /* width height colours characters-per-pixel */
+ ". c None",
+ "B c #000000",
+ "* c #FFFF00",
+ "...BBBBBBBBBB....",
+ "..B**********B...",
+ ".B*****BBBB***B..",
+ "B*****BB*******B.",
+ "B****BB********B.",
+ "B****B*********B.",
+ "B****BBBBB*****B.",
+ "B****BB**BB****B.",
+ "B****B****B****B.",
+ "B****B****B****B.",
+ "B****BB**BB****B.",
+ ".B****BBBB****B..",
+ "..B**********B...",
+ "...BBBBBBBBBB...."
+};
+static gchar * aszMarkerImage7[] =
+{
+ "17 14 3 1", /* width height colours characters-per-pixel */
+ ". c None",
+ "B c #000000",
+ "* c #FFFF00",
+ "...BBBBBBBBBB....",
+ "..B**********B...",
+ ".B***BBBBBB***B..",
+ "B*********B****B.",
+ "B********B*****B.",
+ "B*******B******B.",
+ "B*******B******B.",
+ "B******B*******B.",
+ "B*****B********B.",
+ "B*****B********B.",
+ "B****B*********B.",
+ ".B***B********B..",
+ "..B**********B...",
+ "...BBBBBBBBBB...."
+};
+static gchar * aszMarkerImage8[] =
+{
+ "17 14 3 1", /* width height colours characters-per-pixel */
+ ". c None",
+ "B c #000000",
+ "* c #FFFF00",
+ "...BBBBBBBBBB....",
+ "..B**********B...",
+ ".B****BBBB****B..",
+ "B****BB**BB****B.",
+ "B****B****B****B.",
+ "B****BB**BB****B.",
+ "B*****BBBB*****B.",
+ "B****BB**BB****B.",
+ "B****B****B****B.",
+ "B****B****B****B.",
+ "B****BB**BB****B.",
+ ".B****BBBB****B..",
+ "..B**********B...",
+ "...BBBBBBBBBB...."
+};
+static gchar * aszMarkerImage9[] =
+{
+ "17 14 3 1", /* width height colours characters-per-pixel */
+ ". c None",
+ "B c #000000",
+ "* c #FFFF00",
+ "...BBBBBBBBBB....",
+ "..B**********B...",
+ ".B****BBBB****B..",
+ "B****BB**BB****B.",
+ "B****B****B****B.",
+ "B****BB**BB****B.",
+ "B*****BBBBB****B.",
+ "B*********B****B.",
+ "B*********B****B.",
+ "B********BB****B.",
+ "B*******BB*****B.",
+ ".B***BBBB*****B..",
+ "..B**********B...",
+ "...BBBBBBBBBB...."
+};
+
+static gchar ** aszMarkerImages[]=
+{
+ aszMarkerImage0,aszMarkerImage1,aszMarkerImage2,aszMarkerImage3,aszMarkerImage4,
+ aszMarkerImage5,aszMarkerImage6,aszMarkerImage7,aszMarkerImage8,aszMarkerImage9
+};
+
+
+/* return a FileData structure for a file
+ * if not come across this file before then create one, otherwise return existing structure with
+ * data in it
+ * returns NULL on error
+*/
+static FileData * GetFileData(gchar *pcFileName)
+{
+ FileData *fdTemp=fdKnownFilesSettings;
+ gint i;
+
+ /* First handle if main pointer doesn't point to anything */
+ if(fdTemp==NULL)
+ {
+ if((fdKnownFilesSettings=(FileData*)(g_malloc(sizeof *fdTemp)))!=NULL)
+ {
+ fdKnownFilesSettings->pcFileName=g_strdup(pcFileName);
+ for(i=0;i<10;i++)
+ fdKnownFilesSettings->iBookmark[i]=-1;
+
+ fdKnownFilesSettings->pcFolding=NULL;
+ fdKnownFilesSettings->LastChangedTime=-1;
+ fdKnownFilesSettings->NextNode=NULL;
+ }
+ return fdKnownFilesSettings;
+ }
+
+ /* move through chain to the correct entry or the end of a chain */
+ while(TRUE)
+ {
+ /* if have found relavent FileData, then exit */
+ if(utils_str_equal(pcFileName,fdTemp->pcFileName)==TRUE)
+ return fdTemp;
+
+ /* if end of chain, then add new entry, and return it. */
+ if(fdTemp->NextNode==NULL)
+ {
+ if((fdTemp->NextNode=(FileData*)(g_malloc(sizeof *fdTemp)))!=NULL)
+ {
+ fdTemp->NextNode->pcFileName=g_strdup(pcFileName);
+ for(i=0;i<10;i++)
+ fdTemp->NextNode->iBookmark[i]=-1;
+
+ fdTemp->NextNode->pcFolding=NULL;
+ fdTemp->NextNode->LastChangedTime=-1;
+ fdTemp->NextNode->NextNode=NULL;
+ }
+ return fdTemp->NextNode;
+
+ }
+ fdTemp=fdTemp->NextNode;
+
+ }
+}
+
+
+/* save settings (preferences, file data such as fold states, marker positions) */
+static void SaveSettings(void)
+{
+ GKeyFile *config = NULL;
+ gchar *config_file = NULL;
+ gchar *data;
+ FileData* fdTemp=fdKnownFilesSettings;
+ gchar *cKey;
+ gchar szMarkers[1000];
+ gchar *pszMarkers;
+ gint i,iFiles=0;
+
+ /* create new config from default settings */
+ config=g_key_file_new();
+
+ /* now set settings */
+ g_key_file_set_boolean(config,"Settings","Center_When_Goto_Bookmark",bCenterWhenGotoBookmark);
+ g_key_file_set_boolean(config,"Settings","Remember_Folds",bRememberFolds);
+
+ /* now save file data */
+ while(fdTemp!=NULL)
+ {
+ cKey=g_strdup_printf("A%d",iFiles);
+ /* save filename */
+ g_key_file_set_string(config,"FileData",cKey,fdTemp->pcFileName);
+ /* save folding data */
+ cKey[0]='B';
+ if(NZV(fdTemp->pcFolding))
+ g_key_file_set_string(config,"FileData",cKey,fdTemp->pcFolding);
+
+ /* save last saved time */
+ cKey[0]='C';
+ g_key_file_set_integer(config,"FileData",cKey,fdTemp->LastChangedTime);
+ /* save bookmarks */
+ cKey[0]='D';
+ pszMarkers=szMarkers;
+ pszMarkers[0]=0;
+ for(i=0;i<10;i++)
+ {
+ if(fdTemp->iBookmark[i]!=-1)
+ {
+ sprintf(pszMarkers,"%d",fdTemp->iBookmark[i]);
+ while(pszMarkers[0]!=0)
+ pszMarkers++;
+ }
+
+ pszMarkers[0]=',';
+ pszMarkers[1]=0;
+ pszMarkers++;
+ }
+ /* don't need a ',' after last position (have '\0' instead) */
+ pszMarkers--;
+ pszMarkers[0]=0;
+ g_key_file_set_string(config,"FileData",cKey,szMarkers);
+
+ g_free(cKey);
+
+ /* point to next FileData entry or NULL if end of chain */
+ iFiles++;
+ fdTemp=fdTemp->NextNode;
+ }
+
+ /* turn config into data */
+ data=g_key_file_to_data(config,NULL,NULL);
+
+ /* calculate setting directory name */
+ config_file=g_build_filename(geany->app->configdir,"plugins","Geany_Numbered_Bookmarks",NULL);
+ /* ensure directory exists */
+ g_mkdir_with_parents(config_file,0755);
+
+ /* make config_file hold name of settings file */
+ setptr(config_file,g_build_filename(config_file,"settings.conf",NULL));
+
+ /* write data */
+ utils_write_file(config_file, data);
+
+ /* free memory */
+ g_free(config_file);
+ g_key_file_free(config);
+ g_free(data);
+}
+
+
+/* load settings (preferences, file data, and macro data) */
+static void LoadSettings(void)
+{
+ gchar *pcTemp;
+ gchar *pcKey;
+ gint i,l;
+ gchar *config_file=NULL;
+ GKeyFile *config=NULL;
+ FileData *fdTemp;
+
+ /* Make config_file hold directory name of settings file */
+ config_file=g_build_filename(geany->app->configdir,"plugins","Geany_Numbered_Bookmarks",NULL);
+ /* ensure directory exists */
+ g_mkdir_with_parents(config_file,0755);
+
+ /* make config_file hold name of settings file */
+ setptr(config_file,g_build_filename(config_file,"settings.conf",NULL));
+
+ /* either load settings file, or create one from default */
+ config=g_key_file_new();
+ if(!g_key_file_load_from_file(config,config_file, G_KEY_FILE_KEEP_COMMENTS,NULL))
+ g_key_file_load_from_data(config,default_config,sizeof(default_config),
+ G_KEY_FILE_KEEP_COMMENTS,NULL);
+
+ /* extract settings */
+ bCenterWhenGotoBookmark=utils_get_setting_boolean(config,"Settings",
+ "Center_When_Goto_Bookmark",FALSE);
+ bRememberFolds=utils_get_setting_boolean(config,"Settings","Remember_Folds",FALSE);
+
+ /* extract data about files */
+ i=0;
+ while(TRUE)
+ {
+ pcKey=g_strdup_printf("A%d",i);
+ i++;
+ /* get filename */
+ pcTemp=(gchar*)(utils_get_setting_string(config,"FileData",pcKey,NULL));
+ /* if null then have reached end of files */
+ if(pcTemp==NULL)
+ {
+ g_free(pcKey);
+ break;
+ }
+
+ fdTemp=GetFileData(pcTemp);
+ /* get folding data */
+ pcKey[0]='B';
+ fdTemp->pcFolding=(gchar*)(utils_get_setting_string(config,"FileData",pcKey,NULL));
+ /* load last saved time */
+ pcKey[0]='C';
+ fdTemp->LastChangedTime=utils_get_setting_integer(config,"FileData",pcKey,-1);
+ /* get bookmarks */
+ pcKey[0]='D';
+ pcTemp=(gchar*)(utils_get_setting_string(config,"FileData",pcKey,NULL));
+ g_free(pcKey);
+ /* pcTemp contains comma seperated numbers (or blank for -1) */
+ pcKey=pcTemp;
+ if(pcTemp!=NULL) for(l=0;l<10;l++)
+ {
+ /* Bookmark entries are initialized to -1, so only need to parse non-empty slots */
+ if(pcKey[0]!=',' && pcKey[0]!=0)
+ {
+ fdTemp->iBookmark[l]=strtoll(pcKey,NULL,10);
+ while(pcKey[0]!=0 && pcKey[0]!=',')
+ pcKey++;
+ }
+
+ pcKey++;
+ }
+ g_free(pcTemp);
+ }
+
+ /* free memory */
+ g_free(config_file);
+ g_key_file_free(config);
+}
+
+
+/* Define Markers for an editor */
+static void DefineMarkers(ScintillaObject* sci)
+{
+ gint i;
+ for(i=0;i<10;i++)
+ scintilla_send_message(sci,SCI_MARKERDEFINEPIXMAP,i+BOOKMARK_BASE,
+ (glong)(aszMarkerImages[i]));
+}
+
+
+/* Make sure that have setup markers if not come across this particular editor
+ * Keep track of editors we've encountered and set markers for
+*/
+static void CheckEditorSetup(void)
+{
+ SCIPOINTERHOLDER *sciTemp;
+ ScintillaObject* sci=document_get_current()->editor->sci;
+
+ /* no recorded editors so make note of editor */
+ if(sciList==NULL)
+ {
+ if((sciList=(SCIPOINTERHOLDER *)(g_malloc(sizeof *sciTemp)))!=NULL)
+ {
+ sciList->sci=sci;
+ sciList->NextNode=NULL;
+ DefineMarkers(sci);
+ }
+
+ return;
+ }
+
+ sciTemp=sciList;
+ while(sciTemp->NextNode!=NULL)
+ {
+ /* if have come across this editor before, then it will have had it's markers set and we
+ * don't need to do any more
+ */
+ if(sciTemp->sci==sci)
+ return;
+
+ sciTemp=sciTemp->NextNode;
+ }
+ /* if have come across this editor before, then it will have had it's markers set and we don't
+ * need to do any more
+ */
+ if(sciTemp->sci==sci)
+ return;
+
+ /* not come across this editor */
+ if((sciTemp->NextNode=g_malloc(sizeof *sciTemp->NextNode))!=NULL)
+ {
+ sciTemp->NextNode->sci=sci;
+ sciTemp->NextNode->NextNode=NULL;
+ DefineMarkers(sci);
+ }
+}
+
+
+/* handler for when a document has been opened
+ * this checks to see if a document has been altered since it was last saved in geany (as plugin
+ * data may then be out of date for file)
+ * It then applies file settings
+*/
+static void on_document_open(GObject *obj, GeanyDocument *doc, gpointer user_data)
+{
+ FileData *fd;
+ gint i,l=GTK_RESPONSE_ACCEPT,iLineCount;
+ ScintillaObject* sci=doc->editor->sci;
+ struct stat sBuf;
+ GtkWidget *dialog;
+ gchar *cFoldData=NULL;
+ gint iBits,iFlags,iBitCounter;
+
+ /* ensure have markers set */
+ CheckEditorSetup();
+ DefineMarkers(sci);
+
+ /* check to see if file has changed since geany last saved it */
+ fd=GetFileData(doc->file_name);
+ if(stat(doc->file_name,&sBuf)==0 && fd!=NULL && fd->LastChangedTime!=-1 &&
+ fd->LastChangedTime!=sBuf.st_mtime)
+ {
+ /* notify user that file has been changed */
+ dialog=gtk_message_dialog_new(GTK_WINDOW(geany->main_widgets->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_NONE,
+ _("'%s' has been edited since it was last saved by geany. Marker positions may \
+be unreliable and will not be loaded.\nPress Ignore to try an load markers anyway."),
+ doc->file_name);
+ gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Okay"),GTK_RESPONSE_OK);
+ gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Ignore"),GTK_RESPONSE_REJECT);
+ l=gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ }
+
+ switch(l)
+ {
+ /* file not changed since Geany last saved it so saved settings should be fine */
+ case GTK_RESPONSE_ACCEPT:
+ /* now set markers */
+ for(i=0;i<10;i++)
+ if(fd->iBookmark[i]!=-1)
+ scintilla_send_message(sci,SCI_MARKERADD,fd->iBookmark[i],i+BOOKMARK_BASE);
+
+ /* get fold settings if present and want to use them */
+ if(fd->pcFolding==NULL || bRememberFolds==FALSE)
+ break;
+
+ cFoldData=fd->pcFolding;
+
+ /* first ensure fold positions exist */
+ scintilla_send_message(sci,SCI_COLOURISE,0,-1);
+
+ iLineCount=scintilla_send_message(sci,SCI_GETLINECOUNT,0,0);
+
+ /* go through lines setting fold status */
+ for(i=0,iBitCounter=6;i<iLineCount;i++)
+ {
+ iFlags=scintilla_send_message(sci,SCI_GETFOLDLEVEL,i,0);
+ /* ignore non-folding lines */
+ if((iFlags & SC_FOLDLEVELHEADERFLAG)==0)
+ continue;
+
+ /* get next 6 fold states if needed */
+ if(iBitCounter==6)
+ {
+ iBitCounter=0;
+ iBits=base64_char_to_int[(gint)(*cFoldData)];
+ cFoldData++;
+ }
+
+ /* set fold if needed */
+ if(((iBits>>iBitCounter)&1)==0)
+ scintilla_send_message(sci,SCI_TOGGLEFOLD,i,0);
+
+ /* increment counter */
+ iBitCounter++;
+ }
+
+ break;
+ /* file has changed since Geany last saved but, try to load bookmarks anyway */
+ case GTK_RESPONSE_REJECT:
+ iLineCount=scintilla_send_message(sci,SCI_GETLINECOUNT,0,0);
+ for(i=0;i<10;i++)
+ if(fd->iBookmark[i]!=-1 && fd->iBookmark[i]<iLineCount)
+ scintilla_send_message(sci,SCI_MARKERADD,fd->iBookmark[i],i);
+
+ break;
+ default: /* default - don't try to set markers */
+ break;
+ }
+}
+
+
+/* handler for when a document has been saved
+ * This saves off fold state, and marker positions for the file
+*/
+static void on_document_save(GObject *obj, GeanyDocument *doc, gpointer user_data)
+{
+ FileData *fdTemp;
+ gint i,iLineCount,iFlags,iBitCounter=0;
+ ScintillaObject* sci=doc->editor->sci;
+ struct stat sBuf;
+ GByteArray *gbaFoldData=g_byte_array_sized_new(1000);
+ guint8 guiFold=0;
+
+ /* update markerpos */
+ fdTemp=GetFileData(doc->file_name);
+ for(i=0;i<10;i++)
+ fdTemp->iBookmark[i]=scintilla_send_message(sci,SCI_MARKERNEXT,0,1<<(i+BOOKMARK_BASE));
+
+ /* update fold state */
+ iLineCount=scintilla_send_message(sci,SCI_GETLINECOUNT,0,0);
+ /* go through each line */
+ for(i=0;i<iLineCount;i++)
+ {
+ iFlags=scintilla_send_message(sci,SCI_GETFOLDLEVEL,i,0);
+ /* ignore line if not a folding point */
+ if((iFlags & SC_FOLDLEVELHEADERFLAG)==0)
+ continue;
+
+ iFlags=scintilla_send_message(sci,SCI_GETFOLDEXPANDED,i,0);
+ /* remember if folded or not */
+ guiFold|=(iFlags&1)<<iBitCounter;
+ iBitCounter++;
+ if(iBitCounter<6)
+ continue;
+
+ /* if have 6 bits then store these */
+ iBitCounter=0;
+ guiFold=(guint8)base64_int_to_char[guiFold];
+ g_byte_array_append(gbaFoldData,&guiFold,1);
+ guiFold=0;
+ }
+
+ /* flush buffer */
+ if(iBitCounter!=0)
+ {
+ guiFold=(guint8)base64_int_to_char[guiFold];
+ g_byte_array_append(gbaFoldData,&guiFold,1);
+ }
+
+ /* transfer data to text string */
+ fdTemp->pcFolding=g_strndup((gchar*)(gbaFoldData->data),gbaFoldData->len);
+
+ /* free byte array space */
+ g_byte_array_free(gbaFoldData,TRUE);
+
+ /* make note of time last saved */
+ if(stat(doc->file_name,&sBuf)==0)
+ fdTemp->LastChangedTime=sBuf.st_mtime;
+
+ /* save settings */
+ SaveSettings();
+}
+
+
+PluginCallback plugin_callbacks[] =
+{
+ { "document-open", (GCallback) &on_document_open, FALSE, NULL },
+ { "document-save", (GCallback) &on_document_save, FALSE, NULL },
+ { NULL, NULL, FALSE, NULL }
+};
+
+
+/* returns current line number */
+static gint GetLine(ScintillaObject* sci)
+{
+ return scintilla_send_message(sci,SCI_LINEFROMPOSITION,
+ scintilla_send_message(sci,SCI_GETCURRENTPOS,10,0),0);
+}
+
+
+/* handle button presses in the preferences dialog box */
+static void on_configure_response(GtkDialog *dialog, gint response, gpointer user_data)
+{
+ gboolean bSettingsHaveChanged;
+ GtkCheckButton *cb1,*cb2;
+
+ if(response!=GTK_RESPONSE_OK && response!=GTK_RESPONSE_APPLY)
+ return;
+
+ /* retreive pointers to check boxes */
+ cb1=(GtkCheckButton*)(g_object_get_data(G_OBJECT(dialog),"Geany_Numbered_Bookmarks_cb1"));
+ cb2=(GtkCheckButton*)(g_object_get_data(G_OBJECT(dialog),"Geany_Numbered_Bookmarks_cb2"));
+
+ /* first see if settings are going to change */
+ bSettingsHaveChanged=(bRememberFolds!=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb1)));
+ bSettingsHaveChanged|=(bCenterWhenGotoBookmark!=gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(cb2)));
+
+ /* set new settings settings */
+ bRememberFolds=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb1));
+ bCenterWhenGotoBookmark=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb2));
+
+ /* now save new settings if they have changed */
+ if(bSettingsHaveChanged)
+ SaveSettings();
+}
+
+
+/* return a widget containing settings for plugin that can be changed */
+GtkWidget *plugin_configure(GtkDialog *dialog)
+{
+ GtkWidget *vbox;
+ GtkWidget *cb1,*cb2;
+
+ vbox=gtk_vbox_new(FALSE, 6);
+
+ cb1=gtk_check_button_new_with_label(_("remember fold state"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb1),bRememberFolds);
+ gtk_box_pack_start(GTK_BOX(vbox),cb1,FALSE,FALSE,2);
+ /* save pointer to check_button */
+ g_object_set_data(G_OBJECT(dialog),"Geany_Numbered_Bookmarks_cb1",cb1);
+
+ cb2=gtk_check_button_new_with_label(_("Center view when goto bookmark"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb2),bCenterWhenGotoBookmark);
+ gtk_box_pack_start(GTK_BOX(vbox),cb2,FALSE,FALSE,2);
+ /* save pointer to check_button */
+ g_object_set_data(G_OBJECT(dialog),"Geany_Numbered_Bookmarks_cb2",cb2);
+
+ gtk_widget_show_all(vbox);
+
+ g_signal_connect(dialog,"response",G_CALLBACK(on_configure_response),NULL);
+
+ return vbox;
+}
+
+
+/* display help box */
+void plugin_help(void)
+{
+ GtkWidget *dialog,*label,*scroll;
+
+ /* create dialog box */
+ dialog=gtk_dialog_new_with_buttons(_("Numbered Bookmarks help"),
+ GTK_WINDOW(geany->main_widgets->window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK,GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ /* create label */
+ label=gtk_label_new(
+ _("This Plugin implements Numbered Bookmarks in Geany.\n\n"
+ "It allows you to use 10 numbered bookmarks. Normaly if you had more than one \
+bookmark, you would have to cycle through them until you reached the one you wanted. With this \
+plugin you can go straight to the bookmark that you want with a single key combination. To set a \
+numbered bookmark press Ctrl+Shift+a number from 0 to 9. You will see a marker apear next to the \
+line number. If you press Ctrl+Shift+a number on a line that already has that bookmark number then\
+ it removes the bookmark, otherwise it will move the bookmark there if it was set on a different \
+line, or create it if it had not already been set. Only the bookmark with the highest number on a \
+line will be shown, but you can have more than one bookmark per line. This plugin does not \
+interfer with regular bookmarks. When a file is saved, Geany will remember the numbered bookmarks \
+and make sure that they are set the next time you open the file.\n\n"
+ "You can alter the default behaviour of this plugin by selecting Plugin Manager under the \
+Tools menu, selecting this plugin, and cliking Preferences. You can change:\nRemember fold state -\
+ if this is set then this plugin will remember the state of any folds along with the numbered \
+bookmarks and set them when the file is next loaded.\nCenter view when goto bookmark - If this is \
+set it will try to make sure that the numbered bookmark that you are going to is in the center of \
+the screen, otherwise it will simply be on the screen somewhere."));
+ gtk_label_set_line_wrap(GTK_LABEL(label),TRUE);
+ gtk_widget_show(label);
+
+ /* create scrolled window to display label */
+ scroll=gtk_scrolled_window_new(NULL,NULL);
+ gtk_scrolled_window_set_policy((GtkScrolledWindow*)scroll,GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_add_with_viewport((GtkScrolledWindow*)scroll,label);
+
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),scroll);
+ gtk_widget_show(scroll);
+
+ /* set dialog size (leave width default) */
+ gtk_widget_set_size_request(dialog,-1,300);
+
+ /* display the dialog */
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+}
+
+
+/* goto numbered bookmark */
+static void GotoBookMark(gint iBookMark)
+{
+ gint iLine,iLinesVisible,iLineCount;
+ ScintillaObject* sci=document_get_current()->editor->sci;
+
+ iLine=scintilla_send_message(sci,SCI_MARKERNEXT,0,1<<(iBookMark+BOOKMARK_BASE));
+
+ /* ignore if no marker placed for requested bookmark */
+ if(iLine==-1)
+ return;
+
+ /* move to bookmark */
+ scintilla_send_message(sci,SCI_GOTOLINE,iLine,0);
+
+ if(bCenterWhenGotoBookmark==FALSE)
+ return;
+
+ /* try and center bookmark on screen */
+ iLinesVisible=scintilla_send_message(sci,SCI_LINESONSCREEN,0,0);
+ iLineCount=scintilla_send_message(sci,SCI_GETLINECOUNT,0,0);
+ iLine-=iLinesVisible/2;
+ /* make sure view is not beyond start or end of document */
+ if(iLine+iLinesVisible>iLineCount)
+ iLine=iLineCount-iLinesVisible;
+ if(iLine<0)
+ iLine=0;
+
+ scintilla_send_message(sci,SCI_SETFIRSTVISIBLELINE,iLine,0);
+}
+
+
+/* set (or remove) numbered bookmark */
+static void SetBookMark(gint iBookMark)
+{
+ gint iNewLine,iOldLine;
+ ScintillaObject* sci=document_get_current()->editor->sci;
+
+ /* see if already such a bookmark present */
+ iOldLine=scintilla_send_message(sci,SCI_MARKERNEXT,0,1<<(iBookMark+BOOKMARK_BASE));
+ iNewLine=GetLine(sci);
+ /* if no marker then simply add one to current line */
+ if(iOldLine==-1)
+ {
+ CheckEditorSetup();
+ scintilla_send_message(sci,SCI_MARKERADD,iNewLine,iBookMark+BOOKMARK_BASE);
+ }
+ /* else either have to remove marker from current line, or move it to current line */
+ else
+ {
+ /* remove old marker */
+ scintilla_send_message(sci,SCI_MARKERDELETEALL,iBookMark+BOOKMARK_BASE,0);
+ /* add new marker if moving marker */
+ if(iOldLine!=iNewLine) scintilla_send_message(sci,SCI_MARKERADD,iNewLine,iBookMark+BOOKMARK_BASE);
+ }
+}
+
+
+/* handle key press
+ * used to see if macro is being triggered and to control numbered bookmarks
+*/
+static gboolean Key_Released_CallBack(GtkWidget *widget, GdkEventKey *ev, gpointer data)
+{
+ GeanyDocument *doc;
+ gint i;
+
+ doc=document_get_current();
+ if(doc==NULL)
+ return FALSE;
+
+ if(ev->type!=GDK_KEY_RELEASE)
+ return FALSE;
+
+ /* control and number pressed */
+ if(ev->state==4)
+ {
+ i=((gint)(ev->keyval))-'0';
+ if(i<0 || i>9)
+ return FALSE;
+
+ GotoBookMark(i);
+ return TRUE;
+ }
+ /* control+shift+number */
+ if(ev->state==5) {
+ /* could use hardware keycode instead of keyvals but if unable to get keyode then don't
+ * have logical default to fall back on
+ */
+ for(i=0;i<10;i++) if((gint)(ev->keyval)==iShiftNumbers[i])
+ {
+ SetBookMark(i);
+ return TRUE;
+ }
+
+ }
+
+ return FALSE;
+}
+
+
+/* set up this plugin */
+void plugin_init(GeanyData *data)
+{
+ gint i,k,iResults=0;
+ GdkKeymapKey *gdkkmkResults;
+
+ /* Load settings */
+ LoadSettings();
+
+ /* Calculate what shift '0' to '9 will be (£ is above 3 on uk keyboard, but it's # or ~ on us
+ * keyboard.)
+ * there must be an easier way than this of working this out, but I've not figured it out.
+ */
+
+ /* go through '0' to '9', work out hardware keycode, then find out what shift+this keycode
+ * results in
+ */
+ for(i=0;i<10;i++)
+ {
+ /* Get keymapkey data for number key */
+ k=gdk_keymap_get_entries_for_keyval(NULL,'0'+i,&gdkkmkResults,&iResults);
+ /* error retrieving hardware keycode, so leave as standard uk character for shift + number */
+ if(k==0)
+ continue;
+
+ /* unsure, just in case it does return 0 results but reserve memory */
+ if(iResults==0)
+ {
+ g_free(gdkkmkResults);
+ continue;
+ }
+
+ /* now use k to indicate GdkKeymapKey we're after */
+ k=0; /* default if only one hit found */
+ if(iResults>1)
+ /* cycle through results if more than one matches */
+ for(k=0;k<iResults;k++)
+ /* have found number without using shift, ctrl, Alt etc, so shold be it. */
+ if(gdkkmkResults[k].level==0)
+ break;
+
+ /* error figuring out which keycode to use so default to standard uk */
+ if(k==iResults)
+ {
+ g_free(gdkkmkResults);
+ continue;
+ }
+
+ /* set shift pressed */
+ gdkkmkResults[k].level=1;
+ /* now get keycode for shift + number */
+ iResults=gdk_keymap_lookup_key(NULL,&(gdkkmkResults[k]));
+ /* if valid keycode, enter into list of shift + numbers */
+ if(iResults!=0)
+ iShiftNumbers[i]=iResults;
+
+ /* free resources */
+ g_free(gdkkmkResults);
+ }
+
+ /* set key press monitor handle */
+ key_release_signal_id=g_signal_connect(geany->main_widgets->window,"key-release-event",
+ G_CALLBACK(Key_Released_CallBack),NULL);
+}
+
+
+/* clean up on exiting this plugin */
+void plugin_cleanup(void)
+{
+ gint k;
+ guint i;
+ ScintillaObject* sci;
+ SCIPOINTERHOLDER *sciTemp;
+ SCIPOINTERHOLDER *sciNext;
+ FileData *fdTemp=fdKnownFilesSettings;
+ FileData *fdTemp2;
+
+ /* uncouple keypress monitor */
+ g_signal_handler_disconnect(geany->main_widgets->window,key_release_signal_id);
+
+ /* go through all documents removing markers (?needed) */
+ for(i=0;i<GEANY(documents_array)->len;i++)
+ if(documents[i]->is_valid) {
+ sci=documents[i]->editor->sci;
+ for(k=0;k<9;k++)
+ scintilla_send_message(sci,SCI_MARKERDELETEALL,BOOKMARK_BASE+k,0);
+
+ }
+
+ /* Clear memory used for list of editors */
+ sciTemp=sciList;
+ while(sciTemp!=NULL)
+ {
+ sciNext=sciTemp->NextNode;
+ free(sciTemp);
+ sciTemp=sciNext;
+ }
+
+ /* Clear memory used to hold file details */
+ while(fdTemp!=NULL)
+ {
+ /* free filename */
+ g_free(fdTemp->pcFileName);
+ /* free folding information if present */
+ if(fdTemp->pcFolding!=NULL)
+ g_free(fdTemp->pcFolding);
+
+ fdTemp2=fdTemp->NextNode;
+ /* free memory block */
+ g_free(fdTemp);
+ fdTemp=fdTemp2;
+ }
+}
Property changes on: trunk/geany-plugins/geanynumberedbookmarks/src/geanynumberedbookmarks.c
___________________________________________________________________
Added: svn:executable
+ *
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Plugins-Commits
mailing list