0

I wannt to replace a specific word in multiple files. First time i do "C-c c" everything works fine, but when i repeat the command the text is not updated in the newly created files correctly. The files contain same content as the first pair of files(.cpp, .h). I think it is a buffer issue in replace-word-in-string but i dont know how to fix it? I'm a beginner at Elisp please explain in simple terms, thanks for helping me out.

;;Prototype source
(setq sourceCode "//Include Librarys
#include MyClass

//Include Files


//******
//MyClass::MyClass
//******
MyClass::MyClass() {}

//******
//MyClass::~MyClass
//******
MyClass::~MyClass() {}

")

;;Prototype Header
(setq headerCode "#ifndef MYCLASS
#define MYCLASS

//Include Librarys

//Include Files


//Forward declarations


class MyClass {
public:
 MyClass();
 ~MyClass();

private:

};

#endif //!MyClass
")

;;Create CLASS
(global-set-key (kbd "C-c c")
   (defun create-class (directory name)
    (interactive "s(Create a new class) Enter path: 
    sEnter class name: ")

    (setq directory "c:/Programming/") ;only for degugging
    (setq path (concat directory name))
    (setq pathSource (concat path ".cpp"))
    (setq pathHeader (concat path ".h"))

    ;Replace default class name with user specified class name
    (setq sourceCode (replace-word-in-string sourceCode name "MyClass"))

    (setq headerCode (replace-word-in-string headerCode name "MyClass"))

    ;Check if file exist in current directory
    (if (and (file-exists-p pathSource)(file-exists-p pathHeader))
      (message "%s" "Filename already exist, no files where created!")
      (write-region sourceCode nil pathSource) ;Write to files.
      (write-region headerCode nil pathHeader)
      (message "Created source file: %s and created header file: %s" pathSource pathHeader)
    )
  )
) 

(defun replace-word-in-string(string replacementWord searchedWord)
    (with-temp-buffer
      (insert string)
      (goto-char (point-min))
      (while (re-search-forward searchedWord nil t)
        (replace-match replacementWord nil t)
      (setq retString (buffer-string)) ;returns all content in buffer as a   string
      )
   )
retString
)
7
  • 1
    C-c c is reserved for users, it isn't (normally) used by any Emacs packages. So we'll have a hard time helping without knowing what it's bound to. Can you tell us what C-h k C-c c reports?
    – Tyler
    Jul 12, 2016 at 12:45
  • C-h k C-c c reports "C-c c runs the command create-class, which is an interactive Lisp function in `init.el'. It is bound to C-c c. (create-class DIRECTORY NAME) Not documented. [back]" create-class is a function inside "(global-set-key (kbd "C-c c")" Jul 12, 2016 at 13:37
  • 1
    That means create-class was defined in your personal config files - it's not part of emacs or any public package. Where did you get it? Can you post the code? From the help page that C-h k C-c c creates, there should be a link to your init.el. Clicking that will bring you to the source code for the function.
    – Tyler
    Jul 12, 2016 at 13:50
  • I have already posted the code scoll down and you will find 2 functions and one global-set-key, thanks for helping me out :) I have been writing all code by my self. Jul 12, 2016 at 13:53
  • Ah. It looks like you are re-creating snippets. This library might be useful to you. If you want to continue writing your own, you should define your function create-class on its own, at top-level, not nested inside your keybinding. i.e., (defun create-class ...) and (global-set-key (kbd "C-c c") 'create-class)
    – Tyler
    Jul 12, 2016 at 14:08

2 Answers 2

1

I patched up your code so that it works. You'll have to study the differences to see what the problems were. Good luck!

(setq sourceCode "//Include Librarys
#include MyClass
//******
//MyClass::MyClass
//******
MyClass::MyClass() {}
")

File Created:
//Include Librarys
#include HiThere
//******
//HiThere::HiThere
//******
HiThere::HiThere() {}


;;Prototype Header
(setq headerCode "#ifndef MYCLASS
#define MYCLASS
class MyClass {
public:
 MyClass();
 ~MyClass();
};
#endif //!MyClass
")

File Created:
#ifndef MYCLASS
#define MYCLASS
class HiThere {
public:
 HiThere();
 ~HiThere();
};
#endif //!HiThere


(defun create-class (directory name)
  "Create a new class and header file."
  (interactive "s(Create a new class) Enter path:
    sEnter class name: ")

  (let (path pathSource pathHeader)
    ;;(setq directory "c:/Programming/") ;only for degugging
    (setq path (concat directory name))
    (setq pathSource (concat path ".cpp"))
    (setq pathHeader (concat path ".h"))

    ;;Replace default class name with user specified class name
    (setq sourceCode (replace-word-in-string sourceCode name "MyClass"))
    (setq headerCode (replace-word-in-string headerCode name "MyClass"))

    ;;Check if file exist in current directory
    (if (and (file-exists-p pathSource)
             (file-exists-p pathHeader))
        (message "%s" "Filename already exist, no files where created!")
      ;; else no files exist, create the new ones
      (progn
        (with-temp-file pathSource
          (insert sourceCode))
        (with-temp-file pathHeader
          (insert headerCode))
        (message "Created source file: %s\nCreated header file: %s"
                 pathSource pathHeader)
        ))
    ))
;; default-directory is a variable for the current buffer directory
;; test-begin 
(create-class default-directory "HiThere")
"Created source file: /Users/me/Dropbox/../HiThere.cpp
Created header file: /Users/me/Dropbox/.../HiThere.h"
;; test-end

(defun replace-word-in-string(string replacementWord searchedWord)
  (let (retString)
    (with-temp-buffer
      (insert string)
      (goto-char (point-min))
      (while (re-search-forward searchedWord nil t)
        (replace-match replacementWord nil t))
      (setq retString (buffer-string)) ;returns all content in buffer as a string
      )
    retString))
;; test-begin
(replace-word-in-string "How are you?" "busy" "are")
"How busy you?"
;; test-end

Update 1

The problem you are having is that you are using external "free" variables to drag in the template source file, and then resetting those variables to the replaced strings the first time through.

The second time through, the template files have changed, so they no longer contain the "MyClass" searched-for word. So no string replacements occur.

In the code below, I have used two local variables newSource and newHeader to hold the replaced code. This solves the problem of resetting your free variables.

(let (path pathSource pathHeader newSource newHeader)

;;Replace default class name with user specified class name
(setq newSource (replace-word-in-string sourceCode name "MyClass"))
(setq newHeader (replace-word-in-string headerCode name "MyClass"))

    (message "%s" "Filename already exist, no files where created!")
  ;; else no files exist, create the new ones
  (progn
    (with-temp-file pathSource
      (insert newSource))
    (with-temp-file pathHeader
      (insert newHeader))
    (message "Created source file: %s\nCreated header file: %s"
             pathSource pathHeader)
    ))
3
  • Hi! Thanks for helping me out, i appreciate it. But the issue still remains, if you run 2 or more test for the create-class function you will see that it will always print the value for name as it was set in the first test. Jul 16, 2016 at 10:22
  • You were using free variables to hold the template source files, and then overwriting them the first time through your code. After that, they did not contain the "searched for words", so no string replacements occurred.
    – Kevin
    Jul 16, 2016 at 14:04
  • Thanks for the help, good explanation (y). I dont have enough reputation to do an upvote. Jul 16, 2016 at 14:59
0

Here is a working copy of the code(everything is included copy/paste into Emacs and run it), for an explenation of the answere see Kevin posts.

(defun create-class (directory name)
"Create a new class(source and  header file."
(interactive "s(Create a new class) Enter path:
sEnter class name: ")

  (let (path newSourceCode newHeaderCode pathSource pathHeader)
    (setq directory (concat directory "/"))
    (setq path (concat directory name))
    (setq pathSource (concat path ".cpp"))
    (setq pathHeader (concat path ".h"))

    ;;Replace default class name with user specified class name
    (setq newSourceCode (replace-word-in-string sourceCode name "MyClass"))
    (setq newHeaderCode (replace-word-in-string headerCode name "MyClass"))

    ;;Check if file exist in current directory
    (if (and (file-exists-p pathSource)
         (file-exists-p pathHeader))
    (message "%s" "Filename already exist, no files where created!")
   ;; else no files exist, create the new ones
   (progn
    (with-temp-file pathSource
      (insert newSourceCode))
    (with-temp-file pathHeader
      (insert newHeaderCode))
    (message "Created source file: %s\nCreated header file: %s"
             pathSource pathHeader)
    ))
))

(defun replace-word-in-string(string replacementWord searchedWord)
  (let (retString)
    (with-temp-buffer
      (insert string)
      (goto-char (point-min))
      (while (re-search-forward searchedWord nil t)
        (replace-match replacementWord nil t))
      (setq retString (buffer-string)) ;returns all content in buffer as a   string
      )
 retString))

(setq sourceCode "//Include Librarys
#include MyClass.h

//Include Files


//******
//MyClass::MyClass
//******
MyClass::MyClass() {}

//******
//MyClass::~MyClass
//******
MyClass::~MyClass() {}

")

;;Prototype Header
(setq headerCode "#ifndef MYCLASS_H
#define MYCLASS_H

//Include Librarys

//Include Files


//Forward declarations


class MyClass {
public:
  MyClass();
  ~MyClass();

private:

};

#endif //!MYCLASS_H
")

;;Create CLASS
(global-set-key (kbd "C-c c")
  'create-class
) 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.